Changeset 1259:82280e745a89 in freeDiameter
- Timestamp:
- Mar 24, 2014, 9:13:38 PM (10 years ago)
- Branch:
- default
- Phase:
- public
- Location:
- extensions/rt_redirect
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
extensions/rt_redirect/redir_entries.c
r740 r1259 43 43 { 44 44 int i; 45 45 46 46 TRACE_ENTRY(""); 47 47 48 48 /* redirects_usages */ 49 49 memset(&redirects_usages, 0, sizeof(redirects_usages)); 50 50 51 51 for (i = 0; i <= H_U_MAX; i++) { 52 52 CHECK_POSIX( pthread_rwlock_init( &redirects_usages[i].lock, NULL) ); 53 53 fd_list_init( &redirects_usages[i].sentinel, &redirects_usages[i] ); 54 54 } 55 55 56 56 /* initialize the scores */ 57 57 redirects_usages[ DONT_CACHE ].score = FD_SCORE_REDIR_ONCE; … … 73 73 os0_t s; 74 74 size_t l; 75 75 76 76 TRACE_ENTRY("%p %p %d %p %p %zd %p %zd", e, targets, rhu, qry, nh, nhlen, oh, ohlen) 77 77 ASSERT(e && targets && (rhu <= H_U_MAX) && qry && nh && nhlen && oh && ohlen); 78 78 79 79 CHECK_MALLOC( entry = malloc(sizeof(struct redir_entry)) ); 80 80 memset(entry, 0, sizeof(struct redir_entry)); 81 81 82 82 entry->eyec = REDIR_ENTRY_EYEC; 83 83 84 84 CHECK_MALLOC( entry->from.s = os0dup(nh, nhlen) ); 85 85 entry->from.l = nhlen; 86 86 87 87 fd_list_init(&entry->target_peers_list, entry); 88 88 fd_list_move_end(&entry->target_peers_list, targets); 89 89 90 90 fd_list_init(&entry->exp_list, entry); 91 91 92 92 entry->type = rhu; 93 93 fd_list_init(&entry->redir_list, entry); … … 97 97 entry->data.message.msg = qry; 98 98 break; 99 99 100 100 case ALL_SESSION: 101 101 { … … 114 114 } 115 115 break; 116 116 117 117 case ALL_REALM: 118 118 { … … 132 132 } 133 133 break; 134 134 135 135 case REALM_AND_APPLICATION: 136 136 { … … 156 156 } 157 157 break; 158 158 159 159 case ALL_APPLICATION: 160 160 { … … 164 164 } 165 165 break; 166 166 167 167 case ALL_HOST: 168 168 CHECK_MALLOC( entry->data.host.s = os0dup(oh, ohlen) ); 169 169 entry->data.host.l = ohlen; 170 170 break; 171 171 172 172 case ALL_USER: 173 173 { … … 187 187 } 188 188 break; 189 189 190 190 default: 191 191 ASSERT(0); 192 192 return EINVAL; 193 193 } 194 194 195 195 /* We're done */ 196 196 *e = entry; … … 203 203 unsigned long v1 = (unsigned long) d1->message.msg; 204 204 unsigned long v2 = (unsigned long) d2->message.msg; 205 if (v1 > v2) 205 if (v1 > v2) 206 206 return 1; 207 207 if (v1 < v2) … … 211 211 /* Compare two applications (REALM_AND_APPLICATION and ALL_APPLICATION) */ 212 212 static int compare_entries_appl(union matchdata * d1, union matchdata * d2) { 213 if (d1->app.a > d2->app.a) 213 if (d1->app.a > d2->app.a) 214 214 return 1; 215 if (d1->app.a < d2->app.a) 215 if (d1->app.a < d2->app.a) 216 216 return -1; 217 217 return 0; … … 238 238 { 239 239 struct fd_list * li; 240 240 241 241 TRACE_ENTRY("%p", e); 242 242 CHECK_PARAMS(e && (e->eyec == REDIR_ENTRY_EYEC)); 243 243 244 244 /* Write-Lock the line */ 245 245 CHECK_POSIX( pthread_rwlock_wrlock( RWLOCK_REDIR(e) ) ); 246 246 247 247 for (li = redirects_usages[e->type].sentinel.next; li != &redirects_usages[e->type].sentinel; li = li->next) { 248 248 struct redir_entry * n = li->o; … … 251 251 break; 252 252 } 253 253 254 254 fd_list_insert_before(li, &e->redir_list); 255 255 256 256 /* unLock the line */ 257 257 CHECK_POSIX( pthread_rwlock_unlock( RWLOCK_REDIR(e) ) ); … … 265 265 TRACE_ENTRY("%p", e); 266 266 CHECK_PARAMS(e && (e->eyec == REDIR_ENTRY_EYEC)); 267 267 268 268 /* If the entry is linked, lock the rwlock also */ 269 269 if (!FD_IS_LIST_EMPTY(&e->redir_list)) { … … 272 272 CHECK_POSIX( pthread_rwlock_unlock( RWLOCK_REDIR(e) ) ); 273 273 } 274 274 275 275 /* Now unlink from other list */ 276 276 fd_list_unlink(&e->exp_list); 277 277 278 278 /* Empty the targets list */ 279 279 while (!FD_IS_LIST_EMPTY(&e->target_peers_list)) { 280 280 struct redir_host * h = (struct redir_host *)e->target_peers_list.next->o; 281 281 282 282 fd_list_unlink(&h->chain); 283 283 free(h->id); 284 284 free(h); 285 285 } 286 286 287 287 /* Now we can destroy the data safely */ 288 288 switch (e->type) { … … 312 312 return EINVAL; 313 313 } 314 314 315 315 free(e->from.s); 316 316 317 317 free(e); 318 318 return 0; -
extensions/rt_redirect/redir_expiry.c
r740 r1259 41 41 /* Entries by their ascending expiration date, to accelerate the work of the expire thread */ 42 42 static struct fd_list expire_list = FD_LIST_INITIALIZER(expire_list); 43 static pthread_cond_t exp_cnd = PTHREAD_COND_INITIALIZER; 43 static pthread_cond_t exp_cnd = PTHREAD_COND_INITIALIZER; 44 44 45 45 pthread_mutex_t redir_exp_peer_lock = PTHREAD_MUTEX_INITIALIZER; 46 46 47 47 /* The thread that handles expired entries cleanup. */ 48 void * redir_exp_thr_fct(void * arg) 48 void * redir_exp_thr_fct(void * arg) 49 49 { 50 50 fd_log_threadname ( "Redirects/expire" ); … … 53 53 CHECK_POSIX_DO( pthread_mutex_lock(&redir_exp_peer_lock), goto fatal_error ); 54 54 pthread_cleanup_push( fd_cleanup_mutex, &redir_exp_peer_lock ); 55 55 56 56 do { 57 57 struct timespec now; 58 58 struct redir_entry * first; 59 again: 59 again: 60 60 /* Check if there are expiring entries available */ 61 61 if (FD_IS_LIST_EMPTY(&expire_list)) { … … 65 65 goto again; 66 66 } 67 67 68 68 /* Get the pointer to the entry that expires first */ 69 69 first = (struct redir_entry *)(expire_list.next->o); 70 70 71 71 /* Get the current time */ 72 72 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), break ); … … 74 74 /* If first session is not expired, we just wait until it happens */ 75 75 if ( TS_IS_INFERIOR( &now, &first->timeout ) ) { 76 77 CHECK_POSIX_DO2( pthread_cond_timedwait( &exp_cnd, &redir_exp_peer_lock, &first->timeout ), 76 77 CHECK_POSIX_DO2( pthread_cond_timedwait( &exp_cnd, &redir_exp_peer_lock, &first->timeout ), 78 78 ETIMEDOUT, /* ETIMEDOUT is a normal error, continue */, 79 79 /* on other error, */ break ); 80 80 81 81 /* on wakeup, loop */ 82 82 goto again; 83 83 } 84 84 85 85 /* Now, the first entry in the list is expired; destroy it */ 86 86 87 87 CHECK_FCT_DO( redir_entry_destroy( first ), break ); 88 88 89 89 } while (1); 90 90 91 91 pthread_cleanup_pop( 0 ); 92 92 CHECK_POSIX_DO( pthread_mutex_unlock(&redir_exp_peer_lock), ); 93 93 94 94 fatal_error: 95 95 TRACE_DEBUG(INFO, "A system error occurred in redirect module! Expiry thread is terminating..."); … … 104 104 TRACE_ENTRY("%p %d", e, duration); 105 105 CHECK_PARAMS(e && (e->eyec == REDIR_ENTRY_EYEC) && duration ); 106 106 107 107 /* Unlink in case it was already set before */ 108 108 fd_list_unlink(&e->exp_list); 109 109 110 110 /* Get current time */ 111 111 CHECK_SYS( clock_gettime(CLOCK_REALTIME, &e->timeout) ); 112 112 113 113 /* Add the duration */ 114 114 e->timeout.tv_sec += duration; 115 115 116 116 /* now search the next element in the list */ 117 117 for (li = expire_list.next; li != &expire_list; li = li->next) { 118 118 struct redir_entry * n = li->o; 119 119 120 120 if ( TS_IS_INFERIOR( &e->timeout, &n->timeout ) ) 121 121 break; 122 122 123 123 } 124 124 125 125 /* Insert before this element */ 126 126 fd_list_insert_before(li, &e->exp_list); 127 127 128 128 /* Signal the expiry thread if needed */ 129 129 if (e->exp_list.prev == &expire_list) { /* it is the first element */ 130 130 CHECK_POSIX( pthread_cond_signal(&exp_cnd) ); 131 131 } 132 132 133 133 /* Done */ 134 134 return 0; -
extensions/rt_redirect/redir_fwd.c
r1127 r1259 59 59 int nbrh = 0; 60 60 struct redir_entry * entry; 61 61 62 62 TRACE_ENTRY("%p %p", cbdata, msg); 63 63 64 64 CHECK_PARAMS(msg && *msg); 65 65 66 66 m = *msg; 67 67 68 68 /* First get the header */ 69 69 CHECK_FCT( fd_msg_hdr(m, &hdr) ); 70 70 71 71 /* Check if we have an error */ 72 72 ASSERT(!(hdr->msg_flags & CMD_FLAG_REQUEST)); … … 75 75 return 0; 76 76 } 77 77 78 78 /* Now get the AVPs we are interested in */ 79 79 CHECK_FCT( fd_msg_browse(m, MSG_BRW_FIRST_CHILD, &avp, NULL) ); 80 80 while (avp) { 81 81 struct avp_hdr * ahdr; 82 82 83 83 CHECK_FCT( fd_msg_avp_hdr( avp, &ahdr ) ); 84 84 if (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) { … … 90 90 a_oh = ahdr->avp_value; 91 91 break; 92 92 93 93 case AC_RESULT_CODE: 94 94 /* Parse this AVP */ … … 96 96 ASSERT( ahdr->avp_value ); 97 97 a_rc = ahdr->avp_value; 98 98 99 99 if (a_rc->u32 != ER_DIAMETER_REDIRECT_INDICATION) { 100 100 /* It is not a REDIRECT error, we don't do anything */ … … 102 102 } 103 103 break; 104 104 105 105 case AC_REDIRECT_HOST: 106 106 { … … 112 112 int l4 = 0; 113 113 char proto = 0; 114 114 115 115 /* Parse this AVP */ 116 116 CHECK_FCT( fd_msg_parse_dict ( avp, fd_g_config->cnf_dict, NULL ) ); 117 117 ASSERT( ahdr->avp_value ); 118 118 119 119 nbrh++; 120 121 CHECK_FCT_DO( fd_os_parse_DiameterURI(ahdr->avp_value->os.data, ahdr->avp_value->os.len, 120 121 CHECK_FCT_DO( fd_os_parse_DiameterURI(ahdr->avp_value->os.data, ahdr->avp_value->os.len, 122 122 &id, &len, &secure, &port, &l4, &proto), 123 123 { … … 125 125 break; 126 126 } ); 127 127 128 128 /* Now check if the transport & protocol are supported */ 129 129 if (proto && (proto != 'd')) { … … 137 137 break; 138 138 } 139 139 140 140 /* It looks OK, save this entry. */ 141 141 142 142 CHECK_MALLOC( h = malloc(sizeof(struct redir_host)) ); 143 143 memset(h, 0, sizeof(struct redir_host)); … … 146 146 h->len = len; 147 147 /* later: secure, port */ 148 148 149 149 /* The list is kept ordered by id so that it is faster to compare to candidates later */ 150 150 for (li = task.rh.next; li != &task.rh; li = li->next) { … … 183 183 CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) ); 184 184 } 185 185 186 186 /* Check we have received the necessary information */ 187 187 if (!a_rc) { … … 189 189 goto out; 190 190 } 191 191 192 192 if (!a_oh) { 193 193 TRACE_DEBUG(FULL, "Invalid Diameter answer without an Origin-Host AVP, Redirect module gave up"); 194 194 goto out; 195 195 } 196 196 197 197 if (FD_IS_LIST_EMPTY(&task.rh)) { 198 198 TRACE_DEBUG(FULL, "Diameter answer with a DIAMETER_REDIRECT_INDICATION Result-Code AVP but no valid/supported Redirect-Host AVP, Redirect module gave up"); … … 204 204 goto out; 205 205 } 206 206 207 207 /* It looks like we can process the Redirect indication */ 208 208 209 209 /* Search for the peers we already know */ 210 210 for (li = task.rh.next; li != &task.rh; li = li->next) { 211 211 struct redir_host * h = li->o; 212 212 struct peer_hdr * peer; 213 213 214 214 CHECK_FCT( fd_peer_getbyid( h->id, h->len, 1, &peer ) ); 215 215 if (peer) { … … 221 221 } 222 222 } 223 223 224 224 TRACE_DEBUG(FULL, "Redirect module: received %d Redirect-Hosts, %d are known peers, %d have an OPEN connection", nbrh, known, actives); 225 225 226 226 /* in this version, we only redirect when there are known active peers. TODO: add new peers via fd_peer_add when no active peer is available */ 227 227 228 228 if (!actives) { 229 229 TRACE_DEBUG(INFO, "Unable to comply to Redirect indication: none of the peers included is in OPEN state"); 230 230 goto out; 231 231 } 232 232 233 233 /* From this point, we will re-send the query to a different peer, so stop forwarding the answer here */ 234 234 *msg = NULL; 235 235 236 236 /* Get the query's routing data & add the new error */ 237 237 CHECK_FCT( fd_msg_answ_getq(m, &q) ); … … 239 239 CHECK_FCT( fd_msg_source_get( m, &nh, &nhlen ) ); 240 240 CHECK_FCT( fd_rtd_error_add(rtd, nh, nhlen, a_oh->os.data, a_oh->os.len, a_rc->u32, NULL, NULL) ); 241 241 242 242 /* Create a redir_rule */ 243 243 CHECK_FCT( redir_entry_new(&entry, &task.rh, task.rhu, q, nh, nhlen, a_oh->os.data, a_oh->os.len) ); 244 244 245 245 CHECK_POSIX( pthread_mutex_lock(&redir_exp_peer_lock) ); 246 246 /* Insert in the split list */ … … 253 253 CHECK_FCT( fd_msg_answ_detach(m) ); 254 254 CHECK_FCT( fd_msg_free(m) ); 255 255 256 256 /* Send it */ 257 257 CHECK_FCT( fd_msg_send(&q, NULL, NULL) ); 258 258 259 259 /* Done! */ 260 260 261 261 out: 262 262 while (!FD_IS_LIST_EMPTY(&task.rh)) { … … 266 266 free(h); 267 267 } 268 268 269 269 return 0; 270 270 -
extensions/rt_redirect/redir_out.c
r1216 r1259 41 41 { 42 42 TRACE_ENTRY("%d %p %p %p", type, msg, data, nodata); 43 43 44 44 /* Initialize the data area */ 45 45 memset(data, 0, sizeof(union matchdata)); 46 46 *nodata = 0; 47 47 48 48 /* Now, find the appropriate information, depending on type */ 49 49 switch (type) { … … 51 51 data->message.msg = msg; 52 52 break; 53 53 54 54 case ALL_SESSION: 55 55 { … … 65 65 } 66 66 break; 67 67 68 68 case ALL_REALM: 69 69 { … … 82 82 } 83 83 break; 84 84 85 85 case REALM_AND_APPLICATION: 86 86 { … … 96 96 data->realm_app.s = ahdr->avp_value->os.data; 97 97 data->realm_app.l = ahdr->avp_value->os.len; 98 98 99 99 /* and then the application */ 100 100 { … … 107 107 } 108 108 break; 109 109 110 110 case ALL_APPLICATION: 111 111 { … … 116 116 } 117 117 break; 118 118 119 119 case ALL_HOST: 120 120 /* This is more complex, we need to match with all candidates in each rule, it'll be done later */ 121 121 break; 122 122 123 123 case ALL_USER: 124 124 { … … 137 137 } 138 138 break; 139 139 140 140 default: 141 141 ASSERT(0); … … 153 153 struct rtd_candidate * c_oh = NULL; 154 154 int cmp; 155 155 156 156 TRACE_ENTRY("%p %p %p", e, msg, candidates); 157 157 ASSERT( e && msg && candidates ); 158 158 159 159 if (FD_IS_LIST_EMPTY(candidates)) { 160 160 TRACE_DEBUG(ANNOYING, "Skip Redirect rule since candidates list is empty"); 161 161 return 0; 162 162 } 163 163 164 164 /* Now search common peers between e->target_peers_list and candidates */ 165 165 TRACE_DEBUG(ANNOYING, "Message %p matches a Redirect rule (t:%d, @%p), processing candidates list", msg, e->type, e); 166 166 167 167 /* First, decrease the score of the host that we received the previous Redirect from, in case it is in the list */ 168 168 for (lic = candidates->next; lic != candidates; lic = lic->next) { 169 169 struct rtd_candidate * cand = (struct rtd_candidate *) lic; 170 170 171 171 /* Special case: ALL_HOST rules: we decrease the score of the Origin-Host if present */ 172 172 if (e->type == ALL_HOST) { … … 179 179 } 180 180 } 181 181 182 182 cmp = fd_os_cmp(cand->diamid, cand->diamidlen, e->from.s, e->from.l); 183 183 if (!cmp) { … … 185 185 cand->score += FD_SCORE_SENT_REDIRECT; 186 186 } 187 188 } 189 187 188 } 189 190 190 if ((e->type == ALL_HOST) && (c_oh == NULL)) { 191 191 /* The rule does not apply, we're done */ 192 192 return 0; 193 193 } 194 194 195 195 /* for each candidate, if it is found in the target_peers list, we add the rule's score to this candidate */ 196 196 for (lic = candidates->next; lic != candidates; lic = lic->next) { 197 197 /* the candidates list is not guaranteed to be ordered at this time, so we cannot avoid the two imbricated loops */ 198 198 struct rtd_candidate * cand = (struct rtd_candidate *) lic; 199 199 200 200 /* Is this candidate in the "Redirect-Host" list ? We must search caseinsentive here. */ 201 201 for (lirh = e->target_peers_list.next; lirh != &e->target_peers_list; lirh = lirh->next) { 202 202 struct redir_host * host = lirh->o; 203 203 int cont; 204 204 205 205 cmp = fd_os_almostcasesrch( cand->diamid, cand->diamidlen, host->id, host->len, &cont ); 206 206 207 207 if (cmp == 0) { 208 208 TRACE_DEBUG(FULL, "Redirect msg %p: peer '%.*s' += %d (rule t:%d @%p)", msg, (int)cand->diamidlen, cand->diamid, redirects_usages[e->type].score, e->type, e); … … 214 214 } 215 215 } 216 216 217 217 return 0; 218 218 } … … 224 224 int i, ret = 0; 225 225 struct msg * msg = *pmsg; 226 226 227 227 TRACE_ENTRY("%p %p %p", cbdata, msg, candidates); 228 228 229 229 for (i = 0; i <= H_U_MAX; i++) { 230 230 /* Lock the line. We write lock in case of DONT_CACHE so we can directly unlink the entry. read in other cases is sufficient */ … … 234 234 CHECK_POSIX( pthread_rwlock_rdlock( &redirects_usages[i].lock ) ); 235 235 } 236 236 237 237 if (!FD_IS_LIST_EMPTY(&redirects_usages[i].sentinel)) { 238 238 union matchdata data; 239 239 int nodata; /* The message does not allow to apply this rule, skip */ 240 240 241 241 /* Retrieve the data that may match in the message */ 242 242 CHECK_FCT_DO( ret = get_data_to_match(i, msg, &data, &nodata), goto out ); 243 243 244 244 /* If this message may match some of our rules */ 245 245 if (!nodata) { … … 248 248 for (li = redirects_usages[i].sentinel.next; li != &redirects_usages[i].sentinel; li = li->next) { 249 249 struct redir_entry * e = li->o; 250 250 251 251 /* Does it match ? */ 252 252 if (i != ALL_HOST) { /* this one is an exception, we handle it separately */ … … 257 257 break; 258 258 } 259 259 260 260 /* This rule matches (or we are in ALL_HOST), apply */ 261 261 CHECK_FCT_DO( ret = apply_rule(e, msg, candidates), goto out ); 262 262 263 263 /* If this was a DONT_CACHE rule, we unlink it, so that it will not be used again */ 264 264 if (i == DONT_CACHE) { 265 265 li=li->prev; 266 266 fd_list_unlink( li->next ); 267 /* We cannot delete here without taking the mutex, which would mean we have first to release the lock... 267 /* We cannot delete here without taking the mutex, which would mean we have first to release the lock... 268 268 just let expiry garbage collet the rule */ 269 269 } 270 270 } 271 271 } 272 273 } 274 out: 272 273 } 274 out: 275 275 CHECK_POSIX( pthread_rwlock_unlock( &redirects_usages[i].lock ) ); 276 276 if (ret) 277 277 return ret; 278 278 } 279 279 280 280 return 0; 281 281 } -
extensions/rt_redirect/rt_redir.c
r740 r1259 47 47 { 48 48 TRACE_ENTRY(""); 49 49 50 50 /* Dictionary objects */ 51 51 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Destination-Realm", &redir_dict_dr, ENOENT) ); … … 54 54 /* Initialize the entries array */ 55 55 CHECK_FCT( redir_entry_init() ); 56 56 57 57 /* Start the expire thread */ 58 58 CHECK_POSIX( pthread_create( &exp_thr, NULL, redir_exp_thr_fct, NULL ) ); 59 59 60 60 /* Register the callback that receives the answers and processes when it contains a Redirect indication. */ 61 61 CHECK_FCT( fd_rt_fwd_register ( redir_fwd_cb, NULL, RT_FWD_ANS, &fwd_hdl ) ); … … 73 73 { 74 74 int i; 75 75 76 76 /* Unregister the callbacks */ 77 77 if (fwd_hdl) { … … 81 81 CHECK_FCT_DO( fd_rt_out_unregister(out_hdl, NULL), ); 82 82 } 83 83 84 84 /* Stop the expiry thread */ 85 85 CHECK_FCT_DO( fd_thr_term(&exp_thr), ); 86 86 87 87 /* Empty all entries */ 88 88 CHECK_POSIX_DO( pthread_mutex_lock(&redir_exp_peer_lock), ); … … 98 98 } 99 99 CHECK_POSIX_DO( pthread_mutex_unlock(&redir_exp_peer_lock), ); 100 100 101 101 return; 102 102 } -
extensions/rt_redirect/rt_redir.h
r1235 r1259 39 39 /* There are 2 locks in this module. The priority is established as follow to avoid deadlocks: 40 40 exp_peer mutex > usages rwlock. 41 (e.g., the rwlock can be taken while holding the mutex, but not the other way) 41 (e.g., the rwlock can be taken while holding the mutex, but not the other way) 42 42 */ 43 43 … … 59 59 /* Expiration time set for DONT_CACHE tasks, so that the entry is found when the code is called back */ 60 60 #define DEFAULT_EXPIRE_TIME 10 /* seconds */ 61 61 62 62 /* Structure to store a parsed Redirect-Host */ 63 63 struct redir_host { 64 struct fd_list chain; 65 64 struct fd_list chain; 65 66 66 DiamId_t id; /* malloc'd */ 67 67 size_t len; 68 /* We don't use the following yet because we don't support dynamic new connections 68 /* We don't use the following yet because we don't support dynamic new connections 69 69 int secure; 70 70 uint16_t port; … … 117 117 } user; 118 118 }; 119 119 120 120 121 121 /* Structure to store a Redirect indication */ 122 122 struct redir_entry { 123 123 uint32_t eyec; /* must be REDIR_ENTRY_EYEC, used for debug only */ 124 124 125 125 struct { 126 126 os0_t s; /* alloc'd, must be freed */ … … 132 132 struct timespec timeout; /* When does this entry expires? */ 133 133 struct fd_list exp_list; /* chain in the expire_list list, ordered by expiration date, protected by exp_peer_lock */ 134 134 135 135 enum redir_h_u type; /* Type of this entry */ 136 136 struct fd_list redir_list; /* link in redirects_usages lists. Lists are ordered by the data value. Protected by rw locks */
Note: See TracChangeset
for help on using the changeset viewer.