/[radius]/radius/radiusd/request.c
ViewVC logotype

Diff of /radius/radiusd/request.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.25 by gray, Sat Dec 21 14:01:52 2002 UTC revision 1.26 by gray, Fri Apr 18 05:27:10 2003 UTC
# Line 1  Line 1 
1  /* This file is part of GNU RADIUS.  /* This file is part of GNU Radius.
2     Copyright (C) 2000,2001 Sergey Poznyakoff     Copyright (C) 2002,2003 Sergey Poznyakoff
3        
4     This program is free software; you can redistribute it and/or modify     GNU Radius is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.     (at your option) any later version.
8        
9     This program is distributed in the hope that it will be useful,     GNU Radius is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.     GNU General Public License for more details.
13        
14     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software Foundation,     along with GNU Radius; if not, write to the Free Software Foundation,
16     Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */     Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17    
18  #define RADIUS_MODULE_REQUEST_C  #define RADIUS_MODULE_REQUEST_C
19    
 #ifndef lint  
 static char rcsid[] =  
 "@(#) $Id$";  
 #endif  
   
20  #ifdef HAVE_CONFIG_H  #ifdef HAVE_CONFIG_H
21  # include <config.h>  # include <config.h>
22  #endif  #endif
23    #include <sys/types.h>
24    #include <errno.h>
25  #include <radiusd.h>  #include <radiusd.h>
26    #include <radsql.h>
27    #include <list.h>
28    
29  extern struct request_class request_class[];  struct request_class request_class[] = {
30            { "AUTH", 0, MAX_REQUEST_TIME, CLEANUP_DELAY,
31              radius_req_decode,   /* Decoder */
32              radius_respond,      /* Handler */
33              radius_req_xmit,     /* Retransmitter */
34              radius_req_cmp,      /* Comparator */
35              radius_req_free,     /* Deallocator */
36              radius_req_drop,     /* Drop function */
37              rad_sql_cleanup,  /* Cleanup function */
38              radius_req_failure,  /* Failure indicator */
39            },
40            { "ACCT", 0, MAX_REQUEST_TIME, CLEANUP_DELAY,
41              radius_req_decode,   /* Decoder */
42              radius_respond,      /* Handler */
43              radius_req_xmit,     /* Retransmitter */
44              radius_req_cmp,      /* Comparator */
45              radius_req_free,     /* Deallocator */
46              radius_req_drop,     /* Drop function */
47              rad_sql_cleanup,  /* Cleanup function */
48              radius_req_failure,  /* Failure indicator */
49            },
50            { "PROXY",0, MAX_REQUEST_TIME, CLEANUP_DELAY,
51              radius_req_decode,   /* Decoder */
52              rad_proxy,        /* Handler */
53              radius_req_xmit,     /* Retransmitter */
54              radius_req_cmp,      /* Comparator */
55              radius_req_free,     /* Deallocator */  
56              proxy_retry,      /* Drop function */
57              NULL,             /* Cleanup function */
58              NULL,             /* Failure indicator */
59            },
60    #ifdef USE_SNMP
61            { "SNMP", 0, MAX_REQUEST_TIME, 0,
62              snmp_decode,      /* Decoder */
63              snmp_answer,      /* Handler */
64              NULL,             /* Retransmitter */
65              snmp_req_cmp,     /* Comparator */
66              snmp_req_free,    /* Deallocator */  
67              snmp_req_drop,    /* Drop function */
68              NULL,             /* Cleanup function */
69              NULL,             /* Failure indicator */
70            },
71    #endif
72            { NULL, }
73    };
74    
75  /* the request queue */  static LIST *request_list; /* List of REQUEST structures */
 static REQUEST *first_request;  
 pthread_mutex_t request_list_mutex = PTHREAD_MUTEX_INITIALIZER;  
   
 #define request_list_block()   Pthread_mutex_lock(&request_list_mutex)  
 #define request_list_unblock() Pthread_mutex_unlock(&request_list_mutex)  
           
 static void request_free(REQUEST *req);  
 static void request_drop(int type, void *data, void *orig_data, int fd,  
                          char *status_str);  
 static void request_xmit(int type, int code, void *data, int fd);  
 static void request_cleanup(int type, void *data);  
 static void *request_thread0(void *arg);  
 static int request_process_command();  
   
 static pthread_mutex_t request_mutex = PTHREAD_MUTEX_INITIALIZER;  
 static pthread_cond_t request_cond = PTHREAD_COND_INITIALIZER;  
   
 static request_thread_command_fp request_command;  
 static void *request_command_arg;  
 static int request_command_count;  
76    
77  int  
78  request_start_thread()  /* ************************* General-purpose functions ********************* */
 {  
         pthread_t tid;  
         int rc = pthread_create(&tid, &thread_attr, request_thread0, NULL);  
         if (rc) {  
                 radlog(L_ERR, _("Can't spawn new thread: %s"),  
                        strerror(rc));  
                 return -1;  
         }  
         num_threads++;  
         debug(1, ("started new thread: %x", (u_long) tid));  
         return 0;  
 }  
79    
80  void  REQUEST *
81  rad_cleanup_thread0(arg)  request_create(int type, int fd, struct sockaddr_in *sa,
82          void *arg;                 u_char *buf, size_t bufsize)
 {  
         filter_cleanup();  
         num_threads--;  
 }  
   
 void *  
 request_thread0(arg)  
         void *arg;  
83  {  {
84          radiusd_thread_init();          void *data;
85            REQUEST *req;
86    
87          pthread_cleanup_push(rad_cleanup_thread0, NULL);          if (request_class[type].decode(sa, buf, bufsize, &data))
88          while (1) {                  return NULL;
89                  REQUEST *req;          req = emalloc(sizeof *req);
90            req->data = data;
91                  request_process_command();          time(&req->timestamp);
92                            req->type = type;
93                  while (req = request_get())          req->addr = *sa;
94                          request_handle(req);          req->rawdata = emalloc(bufsize);
95                  Pthread_mutex_lock(&request_mutex);          memcpy(req->rawdata, buf, bufsize);
96                  debug(1,("thread waiting"));          req->rawsize = bufsize;
97                  pthread_cond_wait(&request_cond, &request_mutex);          req->child_id = 0;
98                  debug(1,("thread waken up"));          req->status = RS_WAITING;
99                  Pthread_mutex_unlock(&request_mutex);          req->fd = fd;
100          }          return req;
         /*NOTREACHED*/  
         pthread_cleanup_pop(1);  
         return NULL;  
101  }  }
102    
103  void  void
104  request_signal()  request_free(REQUEST *req)
 {  
         Pthread_mutex_lock(&request_mutex);  
         debug(100,("Signalling"));  
         pthread_cond_signal(&request_cond);  
         Pthread_mutex_unlock(&request_mutex);  
 }  
   
 int  
 request_process_command()  
105  {  {
106          if (request_command_count > 0 && request_command) {          if (req) {
107                  (*request_command)(request_command_arg);                  request_class[req->type].free(req->data);
108                  request_command_count--;                  efree(req->rawdata);
109                  return 1;                  efree(req);
110          }          }
         return 0;  
111  }  }
112    
113  void  void
114  request_thread_command(fun, data)  request_drop(int type, void *data, void *orig_data, int fd, char *status_str)
         request_thread_command_fp fun;  
         void *data;  
115  {  {
116          Pthread_mutex_lock(&request_mutex);          request_class[type].drop(type, data, orig_data, fd, status_str);
         request_command = fun;  
         request_command_arg = data;  
         request_command_count = num_threads;  
         debug(100,("Signalling"));  
         pthread_cond_broadcast(&request_cond);  
         Pthread_mutex_unlock(&request_mutex);  
117  }  }
118    
119  void  int
120  request_free(req)  request_respond(REQUEST *req)
         REQUEST *req;  
121  {  {
122          request_class[req->type].free(req->data);          return request_class[req->type].respond(req);
         mem_free(req);  
123  }  }
124    
125  void  void
126  request_drop(type, data, orig_data, fd, status_str)  request_xmit(REQUEST *req)
         int type;  
         void *data;  
         void *orig_data;  
         int fd;  
         char *status_str;  
127  {  {
128          request_class[type].drop(type, data, orig_data, fd, status_str);          if (request_class[req->type].xmit)
129  }                  request_class[req->type].xmit(req);
   
 void  
 request_xmit(type, code, data, fd)  
         int type;  
         int code;  
         void *data;  
         int fd;  
 {  
         if (request_class[type].xmit)  
                 request_class[type].xmit(type, code, data, fd);  
   
         switch (type) {  
         case R_AUTH:  
                 stat_inc(auth, ((RADIUS_REQ*)data)->ipaddr, num_dup_req);  
                 break;  
         case R_ACCT:  
                 stat_inc(acct, ((RADIUS_REQ*)data)->ipaddr, num_dup_req);  
         }  
130  }  }
131    
132  int  int
133  request_cmp(type, a, b)  request_cmp(int type, void *a, void *b)
         int type;  
         void *a, *b;  
134  {  {
135          return request_class[type].comp(a, b);          return request_class[type].comp(a, b);
136  }  }
137    
138  void  void
139  request_cleanup(type, data)  request_cleanup(int type, void *data)
         int type;  
         void *data;  
140  {  {
141          if (request_class[type].cleanup)          if (request_class[type].cleanup)
142                  request_class[type].cleanup(type, data);                  request_class[type].cleanup(type, data);
143  }  }
144    
145  /* Request lifecycle:  struct request_closure {
146     A request starts its life in RS_WAITING state. It remains in this          int type;                  /* Type of the request */
147     state until either it is picked up by some thread for processing          void *data;                /* Request contents */
148     or time-to-live seconds expire. When a thread starts processing          time_t curtime;            /* Current timestamp */
149     the request, it changes its state to RS_PENDING. When processing          /* Output: */
150     of the request is finished, its state is changed to RS_COMPLETED.          size_t request_count;      /* Total number of requests */
151     If the request in RS_WAITING state does not switch to RS_PENDING          size_t request_type_count; /* Number of requests of this type */
152     within time-to-live seconds, this request is removed from the queue.  };
153     If the request in RS_PENDING state does not switch to RS_COMPLETED  
154     state within time-to-live seconds, it changes its state to RS_HUNG.  static int
155     If a request remains in RS_HUNG state for more than time-to-live seconds,  _request_iterator(void *item, void *data)
156     it changes its state to RS_DEAD and its handling thread is cancelled.  {
157     If everything goes well, the thread being cancelled will shift          REQUEST *req = item;
158     the request into RS_COMPLETED state and it will be eventually removed          struct request_closure *rp = data;
159     from the queue. Otherwise, if the thread is stuck for good and the          
160     request remains in RS_DEAD state for more than time-to-live seconds          if (req->status == RS_COMPLETED) {
161     the daemon tries to restart itself.                  if (req->timestamp + request_class[req->type].cleanup_delay
162                                 <= rp->curtime) {
163     Finally, a request in RS_COMPLETED state remains in queue for                          debug(1, ("deleting completed %s request",
164     request-cleanup-delay seconds, after which it is removed. */                                    request_class[req->type].name));
165                            list_remove_current(request_list);
166  REQUEST *                          request_free(req);
167  request_put(type, data, activefd, numpending)                          return 0;
168          int type;                  }
169          void *data;          } else if (req->timestamp + request_class[req->type].ttl
170          int activefd;                        <= rp->curtime) {
171          unsigned *numpending;  
172  {                  radlog(L_NOTICE,
173          REQUEST *curreq;                         _("Killing unresponsive %s child %lu"),
174          REQUEST *prevreq;                         request_class[req->type].name,
175          REQUEST *to_replace;                         (unsigned long) req->child_id);
176          time_t curtime;                  rpp_kill(req->child_id, SIGKILL);
177          int request_count, request_type_count;                  rpp_remove(req->child_id);
178                    return 0;
179          time(&curtime);          }
         request_count = request_type_count = 0;  
         curreq = first_request;  
         prevreq = NULL;  
         to_replace = NULL;  
         *numpending = 0;  
           
         /* Block asynchronous access to the list */  
         request_list_block();  
   
         while (curreq != NULL) {  
   
                 if (curreq->status == RS_PENDING)  
                         ++*numpending;  
   
                 if (curreq->status == RS_COMPLETED) {  
                         if (curreq->timestamp +  
                             request_class[curreq->type].cleanup_delay  
                                  <= curtime) {  
                                 debug(1, ("deleting completed %s request",  
                                           request_class[curreq->type].name));  
                                 if (prevreq == NULL) {  
                                         first_request = curreq->next;  
                                         request_free(curreq);  
                                         curreq = first_request;  
                                 } else {  
                                         prevreq->next = curreq->next;  
                                         request_free(curreq);  
                                         curreq = prevreq->next;  
                                 }  
                                 continue;  
                         }  
                 } else if (curreq->timestamp +  
                            request_class[curreq->type].ttl <= curtime) {  
                         switch (curreq->status) {  
                         case RS_WAITING:  
                                 request_drop(curreq->type, NULL, curreq->data,  
                                              curreq->fd,  
                                              _("request timed out in queue"));  
                                   
                                 if (prevreq == NULL) {  
                                         first_request = curreq->next;  
                                         request_free(curreq);  
                                         curreq = first_request;  
                                 } else {  
                                         prevreq->next = curreq->next;  
                                         request_free(curreq);  
                                         curreq = prevreq->next;  
                                 }  
                                 break;  
                                   
                         case RS_PENDING:  
                                 radlog(L_NOTICE,  
                                      _("thread %d (%s) did not respond within %d seconds"),  
                                        curreq->child_id,  
                                        request_class[curreq->type].name,  
                                        request_class[curreq->type].ttl);  
                                 curreq->timestamp = curtime;  
                                 curreq->status = RS_HUNG;  
                                 prevreq = curreq;  
                                 curreq = curreq->next;  
                                 break;  
                                   
                         case RS_HUNG:  
                                 radlog(L_NOTICE,  
                                        _("Killing unresponsive %s thread %d"),  
                                        request_class[curreq->type].name,  
                                        curreq->child_id);  
                                 curreq->status = RS_DEAD;  
                                 /*FIXME: This causes much grief */  
                                 pthread_cancel(curreq->child_id);  
                                 curreq->timestamp = curtime;  
                                 prevreq = curreq;  
                                 curreq = curreq->next;  
                                 break;  
   
                         case RS_DEAD:  
                                 radiusd_primitive_restart(0);  
                         }  
                         continue;  
                 }  
   
                 if (curreq->type == type  
                     && request_cmp(type, curreq->data, data) == 0) {  
                         /* This is a duplicate request.  
                            If the handling process has already finished --  
                            retransmit its results, if possible.  
                            Otherwise drop the request. */  
                         if (curreq->status == RS_COMPLETED)  
                                 request_xmit(type,  
                                              curreq->child_return,  
                                              curreq->data,  
                                              activefd);  
                         else  
                                 request_drop(type, data, curreq->data,  
                                              curreq->fd,  
                                              _("duplicate request"));  
                         request_list_unblock();  
   
                         return NULL;  
                 } else {  
                         if (curreq->type == type) {  
                                 request_type_count++;  
                                 if (type != R_PROXY  
                                     && curreq->status == RS_COMPLETED  
                                     && (to_replace == NULL  
                                         || to_replace->timestamp >  
                                                            curreq->timestamp))  
                                         to_replace = curreq;  
                         }  
                         request_count++;  
                         prevreq = curreq;  
                         curreq = curreq->next;  
                 }  
         }  
180    
181          /* This is a new request */          if (!rp->data)
182          if (request_count >= max_requests) {                  return 0;
183                  if (!to_replace) {          
184                          request_drop(type, data, NULL,          if (req->type == rp->type
185                                       activefd,              && request_cmp(req->type, req->data, data) == 0) {
186                                       _("too many requests in queue"));                  /* This is a duplicate request. If it is already completed,
187                       then hand it over to the child.
188                          request_list_unblock();                     Otherwise drop the request. */
189                          return NULL;                  if (req->status == RS_COMPLETED) {
190                  }                          if (radiusd_master())
191          } else if (request_class[type].max_requests                                  rpp_forward_request(req);
192                     && request_type_count >= request_class[type].max_requests) {                          else
193                  if (!to_replace) {                                  request_xmit(req);
194                          request_drop(type, data, NULL,  
195                                       activefd,                  } else
196                                       _("too many requests of this type"));                          request_drop(req->type, data, req->data, req->fd,
197                                         _("duplicate request"));
198                          request_list_unblock();                  /* Indicate end of request processing */
199                          return NULL;                  rp->data = NULL;
200                  }                  return 0;
201          } else          } else {
202                  to_replace = NULL;                  if (req->type == rp->type)
203                            rp->request_type_count++;
204          /*                  rp->request_count++;
          * Add this request to the list  
          */  
         if (to_replace == NULL) {  
                 curreq = mem_alloc(sizeof *curreq);  
                 curreq->next = first_request;  
                 first_request = curreq;  
         } else {  
                 debug(1, ("replacing request dated %s",  
                           ctime(&to_replace->timestamp)));  
                                   
                 request_class[to_replace->type].free(to_replace->data);  
                 curreq = to_replace;  
205          }          }
206            return 0;
         curreq->timestamp = curtime;  
         curreq->type = type;  
         curreq->data = data;  
         curreq->child_id = 0;  
         curreq->status = RS_WAITING;  
         curreq->fd = activefd;  
           
         debug(1, ("%s request %lu added to the list. %d requests held.",  
                   request_class[type].name,  
                   (u_long) curreq->child_id,  
                   request_count+1));  
   
         request_list_unblock();  
   
         return curreq;  
 }  
   
 REQUEST *  
 request_get()  
 {  
         REQUEST *curreq;  
   
         request_list_block();  
         for (curreq = first_request; curreq; curreq = curreq->next)  
                 if (curreq->status == RS_WAITING) {  
                         curreq->status = RS_PENDING;  
                         curreq->child_id = pthread_self();  
                         time(&curreq->timestamp);  
                         break;  
                 }  
         request_list_unblock();  
         return curreq;  
207  }  }
208    
209  int  int
210  request_flush_list()  request_handle(REQUEST *req, int (*handler)(REQUEST *))
211  {  {
212          REQUEST *curreq;          struct request_closure rc;
         REQUEST *prevreq;  
         time_t  curtime;  
         int     request_count;  
           
         time(&curtime);  
         request_count = 0;  
         curreq = first_request;  
         prevreq = NULL;  
   
         /* Block asynchronous access to the list  
          */  
         request_list_block();  
   
         while (curreq != NULL) {  
                 switch (curreq->status) {  
                 case RS_COMPLETED:  
                 case RS_WAITING:  
                         /* Request completed/waiting, delete it no matter how  
                            long does it reside in the queue */  
                         debug(1, (curreq->status == RS_COMPLETED ?  
                                   "deleting completed %s request" :  
                                   "deleting waiting %s request",  
                                   request_class[curreq->type].name));  
                         if (prevreq == NULL) {  
                                 first_request = curreq->next;  
                                 request_free(curreq);  
                                 curreq = first_request;  
                         } else {  
                                 prevreq->next = curreq->next;  
                                 request_free(curreq);  
                                 curreq = prevreq->next;  
                         }  
                         break;  
213    
214                  case RS_PENDING:          if (!req)
215                          if (curreq->timestamp +                  return 1;
216                              request_class[curreq->type].ttl <= curtime) {          
217                                  radlog(L_NOTICE,          rc.type = req->type;
218                 _("thread %d (%s) did not respond within %d seconds"),          rc.data = req->data;
219                                         curreq->child_id,          time(&rc.curtime);
220                                         request_class[curreq->type].name,          rc.request_count = rc.request_type_count = 0;
221                                         request_class[curreq->type].ttl);  
222                                  curreq->timestamp = curtime;          if (!request_list)
223                                  curreq->status = RS_HUNG;                  request_list = list_create();
224                          }          else
225                          request_count++;                  list_iterate(request_list, _request_iterator, &rc);
                         prevreq = curreq;  
                         curreq = curreq->next;  
                         break;  
                           
                 case RS_HUNG:  
                         if (curreq->timestamp +  
                             request_class[curreq->type].ttl <= curtime) {  
                                 radlog(L_NOTICE,  
                                        _("Killing unresponsive %s thread %d"),  
                                        request_class[curreq->type].name,  
                                        curreq->child_id);  
                                 curreq->status = RS_DEAD;  
                                 /*FIXME: This causes much grief */  
                                 pthread_cancel(curreq->child_id);  
                                 curreq->timestamp = curtime;  
                         }  
                         request_count++;  
                         prevreq = curreq;  
                         curreq = curreq->next;  
                         break;  
226    
227                  case RS_DEAD:          if (!rc.data)
228                          radiusd_primitive_restart(0);                  return 1;
229                          break;          
230            /* This is a new request */
231            if (rc.request_count >= max_requests) {
232                    request_drop(req->type, req->data, NULL, req->fd,
233                                 _("too many requests in queue"));
234                    return 1;
235            } else if (request_class[req->type].max_requests
236                       && rc.request_type_count >= request_class[req->type].max_requests) {
237                    request_drop(req->type, req->data, NULL, req->fd,
238                                 _("too many requests of this type"));
239                    return 1;
240            }
241    
242                  default:          /* Do we have free handlers? */
243                          abort();          if (radiusd_master() && !rpp_ready()) {
244                  }                  radlog(L_NOTICE, _("Maximum number of children active"));
245          }                  return 1;
246            }
247            
248            /* Add request to the queue */
249            debug(1, ("%s request %lu added to the list. %d requests held.",
250                      request_class[req->type].name,
251                      (u_long) req->child_id,
252                      rc.request_count+1));
253    
254          request_list_unblock();          list_append(request_list, req);
255          return request_count;          return (*handler)(req);
256  }  }
257    
258  int  void
259  request_stat_list(stat)  request_set_status(pid_t pid, int status)
         QUEUE_STAT stat;  
260  {  {
261          REQUEST *curreq;          REQUEST *p;
   
         memset(stat, 0, sizeof(QUEUE_STAT));  
           
         /* Block asynchronous access to the list  
          */  
         request_list_block();  
         for (curreq = first_request; curreq != NULL; curreq = curreq->next) {  
                 switch (curreq->status) {  
                 case RS_COMPLETED:  
                         stat[curreq->type].completed++;  
                         break;  
                 case RS_PENDING:  
                         stat[curreq->type].pending++;  
                         break;  
                 case RS_WAITING:  
                         stat[curreq->type].waiting++;  
                         break;  
                 }  
         }  
         request_list_unblock();  
262    
263          return 0;          for (p = list_first(request_list); p; p = list_next(request_list))
264                    if (p->child_id == pid) {
265                            p->status = status;
266                            break;
267                    }
268  }  }
269                            
270    
271  void *  void
272  request_scan_list(type, handler, closure)  request_fail(int type, struct sockaddr_in *addr)
273          int type;  {
274          int (*handler)();          if (request_class[type].failure)
275          void *closure;                  request_class[type].failure(type, addr);
 {  
         REQUEST *curreq;  
   
         for (curreq = first_request; curreq; curreq = curreq->next) {  
                 if (curreq->type == type &&  
                     handler(closure, curreq->data) == 0)  
                         return curreq->data;  
         }  
         return NULL;  
276  }  }
277    
278  void  static int
279  rad_cleanup_thread(arg)  _destroy_request(void *item, void *data)
         void *arg;  
280  {  {
281          REQUEST *curreq = arg;          request_free((REQUEST*)item);
282          debug(1, ("cleaning up request %lu", (u_long) curreq->child_id));          return 0;
         curreq->child_id = 0;  
         curreq->status = RS_COMPLETED;  
         time(&curreq->timestamp);  
         request_cleanup(curreq->type, curreq->data);  
283  }  }
284    
285  void  void
286  request_handle(req)  request_init_queue()
         REQUEST *req;  
287  {  {
288          int rc = 0;          list_destroy(&request_list, _destroy_request, NULL);
289    }
290    
291          if (!req)  void *
292                  return;  request_scan_list(int type, list_iterator_t itr, void *closure)
293    {
294            REQUEST *p;
295    
296          pthread_cleanup_push(rad_cleanup_thread, req);          for (p = list_first(request_list); p; p = list_next(request_list)) {
297          req->status = RS_PENDING;                  if (p->type == type
298          req->child_id = pthread_self();                      && itr(p->data, closure) == 0)
299          time(&req->timestamp);                          return p->data;
300          debug(1, ("setup: %lu: %p",          }
301                    (u_long) req->child_id, request_class[req->type].setup));          return NULL;
         if (request_class[req->type].setup)  
                 rc = request_class[req->type].setup(req);  
         if (rc == 0)  
                 req->child_return = request_class[req->type].handler(req->data,  
                                                                      req->fd);  
         pthread_cleanup_pop(1);  
         log_close();  
         debug(1, ("exiting"));  
302  }  }
   

Legend:
Removed from v.1.25  
changed lines
  Added in v.1.26

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26