📄 request_list.c
字号:
void rl_add(REQUEST *request){ int id = request->packet->id; REQNODE *node; rad_assert(request->container == NULL); request->container = rad_malloc(sizeof(REQNODE)); node = (REQNODE *) request->container; node->req = request; node->prev = NULL; node->next = NULL; if (!request_list[id].first_request) { rad_assert(request_list[id].request_count == 0); request_list[id].first_request = node; request_list[id].last_request = node; } else { rad_assert(request_list[id].request_count != 0); node->prev = request_list[id].last_request; request_list[id].last_request->next = node; request_list[id].last_request = node; } /* * Insert the request into the tree. */ if (rbtree_insert(request_tree, request) == 0) { rad_assert("FAIL" == NULL); } request_list[id].request_count++;}/* * Look up a particular request, using: * * Request ID, request code, source IP, source port, * * Note that we do NOT use the request vector to look up requests. * * We MUST NOT have two requests with identical (id/code/IP/port), and * different vectors. This is a serious error! */REQUEST *rl_find(RADIUS_PACKET *packet){ REQUEST myrequest; myrequest.packet = packet; return rbtree_finddata(request_tree, &myrequest);}/* * See mainconfig.c */extern int proxy_new_listener(void);/* * Add an entry to the proxy tree. * * This is the ONLY function in this source file which may be called * from a child thread. It therefore needs mutexes... */int rl_add_proxy(REQUEST *request){ int i, found, proxy; uint32_t mask; proxy_id_t myid, *entry; myid.dst_ipaddr = request->proxy->dst_ipaddr; myid.dst_port = request->proxy->dst_port; /* * Proxied requests get sent out the proxy FD ONLY. * * FIXME: Once we allocate multiple proxy FD's, move this * code to below, so we can have more than 256 requests * outstanding. */ request->proxy_outstanding = 1; pthread_mutex_lock(&proxy_mutex); /* * Assign a proxy ID. */ entry = rbtree_finddata(proxy_id_tree, &myid); if (!entry) { /* allocate it */ entry = rad_malloc(sizeof(*entry) + sizeof(entry->id) * 255); entry->dst_ipaddr = request->proxy->dst_ipaddr; entry->dst_port = request->proxy->dst_port; entry->index = 0; DEBUG3(" proxy: creating %08x:%d", entry->dst_ipaddr, entry->dst_port); /* * Insert the new home server entry into * the tree. * * FIXME: We don't (currently) delete the * entries, so this is technically a * memory leak. */ if (rbtree_insert(proxy_id_tree, entry) == 0) { DEBUG2("ERROR: Failed to insert entry into proxy Id tree"); free(entry); return 0; } /* * Clear out bits in the array which DO have * proxy Fd's associated with them. We do this * by getting the mask of bits which have proxy * fd's... */ mask = 0; for (i = 0; i < 32; i++) { if (proxy_fds[i] != -1) { mask |= (1 << i); } } rad_assert(mask != 0); /* * Set bits here indicate that the Fd is in use. */ entry->mask = mask; mask = ~mask; /* * Set the bits which are unused (and therefore * allocated). The clear bits indicate that the Id * for that FD is unused. */ for (i = 0; i < 256; i++) { entry->id[i] = mask; } } /* else the entry already existed in the proxy Id tree */ retry: /* * Try to find a free Id. */ found = -1; for (i = 0; i < 256; i++) { /* * Some bits are still zero.. */ if (entry->id[(i + entry->index) & 0xff] != (uint32_t) ~0) { found = (i + entry->index) & 0xff; break; } /* * Hmm... do we want to re-use Id's, when we * haven't seen all of the responses? */ } /* * No free Id, try to get a new FD. */ if (found < 0) { /* * First, see if there were FD's recently allocated, * which we don't know about. */ mask = 0; for (i = 0; i < 32; i++) { if (proxy_fds[i] < 0) continue; mask |= (1 << i); } /* * There ARE more FD's than we know about. * Update the masks for Id's, and re-try. */ if (entry->mask != mask) { /* * New mask always has more bits than * the old one, but never fewer bits. */ rad_assert((entry->mask & mask) == entry->mask); /* * Clear the bits we already know about, * and then or in those bits into the * global mask. */ mask ^= entry->mask; entry->mask |= mask; mask = ~mask; /* * Clear the bits in the Id's for the new * FD's. */ for (i = 0; i < 256; i++) { entry->id[i] &= mask; } /* * And try again to allocate an Id. */ goto retry; } /* else no new Fd's were allocated. */ /* * If all Fd's are allocated, die. */ if (~mask == 0) { radlog(L_ERR|L_CONS, "ERROR: More than 8000 proxied requests outstanding for home server %08x:%d", ntohs(entry->dst_ipaddr), entry->dst_port); return 0; } /* * Allocate a new proxy Fd. This function adds it * into the list of listeners. */ proxy = proxy_new_listener(); if (proxy < 0) { DEBUG2("ERROR: Failed to create a new socket for proxying requests."); return 0; } /* * */ found = -1; for (i = 0; i < 32; i++) { /* * Found a free entry. Save the socket, * and remember where we saved it. */ if (proxy_fds[(proxy + i) & 0x1f] == -1) { proxy_fds[(proxy + i) & 0x1f] = proxy; found = (proxy + i) & 0x1f; break; } } rad_assert(found >= 0); /* i.e. the mask had free bits. */ mask = 1 << found; entry->mask |= mask; mask = ~mask; /* * Clear the relevant bits in the mask. */ for (i = 0; i < 256; i++) { entry->id[i] &= mask; } /* * Pick a random Id to start from, as we've * just guaranteed that it's free. */ found = lrad_rand() & 0xff; } /* * Mark next (hopefully unused) entry. */ entry->index = (found + 1) & 0xff; /* * We now have to find WHICH proxy fd to use. */ proxy = -1; for (i = 0; i < 32; i++) { /* * FIXME: pick a random socket to use? */ if ((entry->id[found] & (1 << i)) == 0) { proxy = i; break; } } /* * There was no bit clear, which we had just checked above... */ rad_assert(proxy != -1); /* * Mark the Id as allocated, for thei Fd. */ entry->id[found] |= (1 << proxy); request->proxy->id = found; rad_assert(proxy_fds[proxy] != -1); request->proxy->sockfd = proxy_fds[proxy]; DEBUG3(" proxy: allocating %08x:%d %d", entry->dst_ipaddr, entry->dst_port, request->proxy->id); if (!rbtree_insert(proxy_tree, request)) { DEBUG2("ERROR: Failed to insert entry into proxy tree"); return 0; } pthread_mutex_unlock(&proxy_mutex); return 1;}/* * Look up a particular request, using: * * Request Id, request code, source IP, source port, * * Note that we do NOT use the request vector to look up requests. * * We MUST NOT have two requests with identical (id/code/IP/port), and * different vectors. This is a serious error! */REQUEST *rl_find_proxy(RADIUS_PACKET *packet){ rbnode_t *node; REQUEST myrequest, *maybe = NULL; RADIUS_PACKET myproxy; /* * If we use the socket FD as an indicator, * then that implicitely contains information * as to our src ipaddr/port, so we don't need * to use that in the comparisons. */ myproxy.sockfd = packet->sockfd; myproxy.id = packet->id; myproxy.dst_ipaddr = packet->src_ipaddr; myproxy.dst_port = packet->src_port;#ifndef NDEBUG myrequest.magic = REQUEST_MAGIC;#endif myrequest.proxy = &myproxy; pthread_mutex_lock(&proxy_mutex); node = rbtree_find(proxy_tree, &myrequest); if (node) { maybe = rbtree_node2data(proxy_tree, node); rad_assert(maybe->proxy_outstanding > 0); maybe->proxy_outstanding--; /* * Received all of the replies we expect. * delete it from both trees. */ if (maybe->proxy_outstanding == 0) { rl_delete_proxy(&myrequest, node); } } pthread_mutex_unlock(&proxy_mutex); return maybe;}/* * Walk over all requests, performing a callback for each request. */int rl_walk(RL_WALK_FUNC walker, void *data){ int id, rcode; REQNODE *curreq, *next; /* * Walk over all 256 ID's. */ for (id = 0; id < 256; id++) { /* * Walk over the request list for each ID. */ for (curreq = request_list[id].first_request; curreq != NULL ; curreq = next) { /* * The callback MIGHT delete the current * request, so we CANNOT depend on curreq->next * to be there, when going to the next element * in the 'for' loop. */ next = curreq->next; rcode = walker(curreq->req, data); if (rcode != RL_WALK_CONTINUE) { return rcode; } } } return 0;}/* * Walk from one request to the next. */REQUEST *rl_next(REQUEST *request){ int id, start_id; int count; /* * If we were passed a request, then go to the "next" one. */ if (request != NULL) { rad_assert(request->magic == REQUEST_MAGIC); /* * It has a "next", return it. */ if (((REQNODE *)request->container)->next != NULL) { return ((REQNODE *)request->container)->next->req; } else { /* * No "next", increment the ID, and look * at that one. */ start_id = request->packet->id + 1; start_id &= 0xff; count = 255; } } else { /* * No input request, start looking at ID 0. */ start_id = 0; count = 256; } /* * Check all ID's, wrapping around at 255. */ for (id = start_id; id < (start_id + count); id++) { /* * This ID has a request, return it. */ if (request_list[id & 0xff].first_request != NULL) { rad_assert(request_list[id&0xff].first_request->req != request); return request_list[id & 0xff].first_request->req; } } /* * No requests at all in the list. Nothing to do. */ DEBUG3("rl_next: returning NULL"); return NULL;}/* * Return the number of requests in the request list. */int rl_num_requests(void){ int id; int request_count = 0; for (id = 0; id < 256; id++) { request_count += request_list[id].request_count; } return request_count;}typedef struct rl_walk_t { time_t now; time_t smallest;} rl_walk_t;/* * Refresh a request, by using proxy_retry_delay, cleanup_delay, * max_request_time, etc. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -