Get rid of "proxyfd", and use the new rad_listen_t structure.
authoraland <aland>
Fri, 28 May 2004 14:42:26 +0000 (14:42 +0000)
committeraland <aland>
Fri, 28 May 2004 14:42:26 +0000 (14:42 +0000)
Allocate more than one proxy FD, when the first one has all Id's
used.  It isn't currently perfect, but it will do.

src/include/radiusd.h
src/include/request_list.h
src/main/mainconfig.c
src/main/radiusd.c
src/main/request_list.c

index b409e28..a8c05fd 100644 (file)
@@ -277,8 +277,6 @@ extern int          log_stripped_names;
 extern int             log_auth_detail;
 extern int             auth_port;
 extern int             acct_port;
-extern int             proxy_port;
-extern int             proxyfd;
 extern const char      *radiusd_version;
 
 /*
index 330de94..c639867 100644 (file)
@@ -12,7 +12,7 @@ extern int rl_init(void);
 extern void rl_delete(REQUEST *request);
 extern void rl_add(REQUEST *request);
 extern REQUEST *rl_find(RADIUS_PACKET *packet);
-extern void rl_add_proxy(REQUEST *request);
+extern int rl_add_proxy(REQUEST *request);
 extern REQUEST *rl_find_proxy(RADIUS_PACKET *packet);
 extern REQUEST *rl_next(REQUEST *request);
 extern int rl_num_requests(void);
index b582d23..c86e87a 100644 (file)
@@ -860,6 +860,59 @@ static int listen_bind(rad_listen_t *this)
        return 0;
 }
 
+
+static int last_proxy_port = 0;
+
+/*
+ *     Externally visible function for creating a new proxy LISTENER.
+ *
+ *     For now, don't take ipaddr or port.
+ */
+int proxy_new_listener(void)
+{
+       int port;
+       rad_listen_t *this;
+
+       this = rad_malloc(sizeof(*this));
+
+       memset(this, 0, sizeof(*this));
+
+       this->ipaddr = mainconfig.myip;
+       this->type = RAD_LISTEN_PROXY;
+
+       /*
+        *      Proxying was not previously defined: die.
+        */
+       if (last_proxy_port == 0) return -1;
+
+       /*
+        *      Keep going until we find an unused port.
+        */
+       for (port = last_proxy_port + 1; port < 64000; port++) {
+               if (listen_bind(this) == 0) {
+                       rad_listen_t **last;
+
+                       last_proxy_port = port;
+
+                       /*
+                        *      Add the new listener to the list of
+                        *      listeners.
+                        */
+                       for (last = &mainconfig.listen;
+                            *last != NULL;
+                            last = &((*last)->next)) {
+                               /* do nothing */
+                       }
+
+                       *last = this;
+                       return this->fd;
+               }
+       }
+
+       return -1;
+}
+
+
 /*
  *     Generate a list of listeners.  Takes an input list of
  *     listeners, too, so we don't close sockets with waiting packets.
@@ -977,6 +1030,7 @@ static int listen_init(const char *filename, rad_listen_t **head)
                     this->port < 64000;
                     this->port++) {
                        if (listen_bind(this) == 0) {
+                               last_proxy_port = this->port;
                                *last = this;
                                return 0;
                        }
index c895834..8a41579 100644 (file)
@@ -91,7 +91,6 @@ int syslog_facility;
 int log_stripped_names;
 int debug_flag = 0;
 int log_auth_detail = FALSE;
-int proxyfd;                   /* should be deleted */
 int need_reload = FALSE;
 int sig_hup_block = FALSE;
 const char *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION ", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
@@ -750,6 +749,11 @@ static REQUEST *request_ok(RADIUS_PACKET *packet, uint8_t *secret,
                rl_add(request);
 
                /*
+                *      ADD IN "server identifier" from "listen"
+                *      directive!
+                */
+
+               /*
                 *      The request passes many of our sanity checks.
                 *      From here on in, if anything goes wrong, we
                 *      send a reject message, instead of dropping the
@@ -1113,7 +1117,6 @@ int main(int argc, char *argv[])
                case RAD_LISTEN_PROXY:
                        DEBUG("Listening on proxy %s:%d",
                              buffer, listener->port);
-                       proxyfd = listener->fd;
                        break;
 
                default:
@@ -1381,8 +1384,8 @@ int main(int argc, char *argv[])
 
                        /*
                         *  Check if we know this client for
-                        *  authfd and acctfd.  Check if we know
-                        *  this proxy for proxyfd.
+                        *  authentication and accounting.  Check if we know
+                        *  this proxy for proxying.
                         */
                        if (listener->type != RAD_LISTEN_PROXY) {
                                RADCLIENT *cl;
@@ -1451,7 +1454,7 @@ int main(int argc, char *argv[])
                        } else {
                                rad_respond(request, fun);
                        }
-               } /* loop over authfd, acctfd, proxyfd */
+               } /* loop over listening sockets*/
 
 #ifdef WITH_SNMP
                if (mainconfig.do_snmp) {
@@ -1489,10 +1492,11 @@ int main(int argc, char *argv[])
 #ifdef HAVE_PTHREAD_H
 
                /*
-                *  Only clean the thread pool if we've spawned child threads.
+                *      Only clean the thread pool if we're spawning
+                *      child threads. 
                 */
                if (spawn_flag) {
-                 thread_pool_clean(time_now);
+                       thread_pool_clean(time_now);
                }
 #endif
 
@@ -1550,6 +1554,16 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
        int finished = FALSE;
        int reprocess = 0;
 
+       rad_assert(request->magic == REQUEST_MAGIC);
+
+       /*
+        *      Don't decode the packet if it's an internal "fake"
+        *      request.  Instead, just skip ahead to processing it.
+        */
+       if ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) != 0) {
+               goto skip_decode;
+       }
+
        /*
         *  Put the decoded packet into it's proper place.
         */
@@ -1563,8 +1577,6 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
                original = NULL;
        }
 
-       rad_assert(request->magic == REQUEST_MAGIC);
-
        /*
         *  Decode the packet, verifying it's signature,
         *  and parsing the attributes into structures.
@@ -1588,20 +1600,20 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
         *  attributes from the list of VP's.
         */
        if (request->proxy) {
-            int rcode;
-            rcode = proxy_receive(request);
-            switch (rcode) {
+               int rcode;
+               rcode = proxy_receive(request);
+               switch (rcode) {
                 default:  /* Don't Do Anything */
-                    break;
+                       break;
                 case RLM_MODULE_FAIL:
-                    /* on error just continue with next request */
-                    goto next_request;
+                       /* on error just continue with next request */
+                       goto next_request;
                 case RLM_MODULE_HANDLED:
-                    /* if this was a replicated request, mark it as
-                     * finished first, because it was postponed
-                     */
-                    goto finished_request;
-            }
+                       /* if this was a replicated request, mark it as
+                        * finished first, because it was postponed
+                        */
+                       goto finished_request;
+               }
 
        } else {
                /*
@@ -1629,8 +1641,9 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
                }
        }
 
+ skip_decode:
        /*
-        *  We should have a User-Name attribute now.
+        *      We should have a User-Name attribute now.
         */
        if (request->username == NULL) {
                request->username = pairfind(request->packet->vps,
@@ -1638,12 +1651,6 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
        }
 
        /*
-        *  We have the semaphore, and have decoded the packet.
-        *  Let's process the request.
-        */
-       rad_assert(request->magic == REQUEST_MAGIC);
-
-       /*
         *  FIXME:  All this lowercase/nospace junk will be moved
         *  into a module after module failover is fully in place
         *
@@ -1673,7 +1680,7 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
        }
 
        /*
-        *  Reprocess if we rejected last time
+        *      Reprocess if we rejected last time
         */
        if ((fun == rad_authenticate) &&
            (request->reply->code == PW_AUTHENTICATION_REJECT)) {
@@ -1694,7 +1701,6 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
          if (strcmp(mainconfig.do_nospace_pass, "after") == 0) {
                  rad_rmspace_pair(request,
                                   pairfind(request->packet->vps, PW_PASSWORD));
-
                  reprocess = 1;
          }
 
@@ -1710,7 +1716,7 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
        }
 
        /*
-        *  Status-Server requests NEVER get proxied.
+        *      Status-Server requests NEVER get proxied.
         */
        if (mainconfig.proxy_requests) {
                if ((request->packet->code != PW_STATUS_SERVER) &&
@@ -1718,7 +1724,7 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
                        int rcode;
 
                        /*
-                        *  Try to proxy this request.
+                        *      Try to proxy this request.
                         */
                        rcode = proxy_send(request);
 
@@ -1784,16 +1790,15 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
                VALUE_PAIR *vp = NULL;
 
                /*
-                *  Perform RFC limitations on outgoing replies.
+                *      Perform RFC limitations on outgoing replies.
                 */
                rfc_clean(request->reply);
 
                /*
-                *  Need to copy Proxy-State from request->packet->vps
+                *      Need to copy Proxy-State from request->packet->vps
                 */
                vp = paircopy2(request->packet->vps, PW_PROXY_STATE);
-               if (vp != NULL)
-                       pairadd(&(request->reply->vps), vp);
+               if (vp) pairadd(&(request->reply->vps), vp);
 
                /*
                 *  If the request isn't an authentication reject, OR
@@ -1832,6 +1837,14 @@ int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun)
 finished_request:
 
        /*
+        *      Don't decode the packet if it's an internal "fake"
+        *      request.  Instead, just skip ahead to processing it.
+        */
+       if ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) != 0) {
+               goto skip_free;
+       }
+
+       /*
         *  We're done handling the request.  Free up the linked
         *  lists of value pairs.  This might take a long time,
         *  so it's more efficient to do it in a child thread,
@@ -1873,6 +1886,7 @@ finished_request:
                pairfree(&request->proxy_reply->vps);
        }
 
+ skip_free:
        DEBUG2("Finished request %d", request->number);
        finished = TRUE;
 
index 7e00765..6bfb0aa 100644 (file)
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * Copyright 2003  The FreeRADIUS server project
+ * Copyright 2003-2004  The FreeRADIUS server project
  */
-
-/*
- *     The functions in this file must be called ONLY from radiusd.c,
- *     in the main server processing thread.  These functions are NOT
- *     thread-safe!
- *
- *     Except for the proxy related code, which is protected by a mutex.
- */
-
 static const char rcsid[] = "$Id$";
 
 #include "autoconf.h"
@@ -109,6 +100,12 @@ static rbtree_t            *proxy_tree;
 static rbtree_t                *proxy_id_tree;
 
 /*
+ *     We keep the proxy FD's here.  The RADIUS Id's are marked
+ *     "allocated" per Id, via a bit per proxy FD.
+ */
+static int             proxy_fds[32];
+
+/*
  *     We can use 256 RADIUS Id's per dst ipaddr/port, per server
  *     socket.  So, to allocate them, we key off of dst ipaddr/port,
  *     and then search the RADIUS Id's, looking for an unused socket.
@@ -124,7 +121,7 @@ typedef struct proxy_id_t {
         *      FIXME: Allocate more proxy sockets when this gets full.
         */
        int             index;
-       int             id[1];  /* really id[256] */
+       uint32_t        id[1];  /* really id[256] */
 } proxy_id_t;
 
 
@@ -212,6 +209,9 @@ static int proxy_cmp(const void *one, const void *two)
        const REQUEST *a = one;
        const REQUEST *b = two;
 
+       rad_assert(a->magic == REQUEST_MAGIC);
+       rad_assert(b->magic == REQUEST_MAGIC);
+
        rad_assert(a->proxy != NULL);
        rad_assert(b->proxy != NULL);
 
@@ -293,6 +293,34 @@ int rl_init(void)
        }
 #endif
 
+       /*
+        *      The Id allocation table is done by bits, so we have
+        *      32 bits per Id.  These bits indicate which entry
+        *      in the proxy_fds array is used for that Id.
+        *
+        *      This design allows 256*32 = 8k requests to be
+        *      outstanding to a home server, before something goes
+        *      wrong.
+        */
+       {
+               int i;
+               rad_listen_t *listener;
+
+               /*
+                *      Mark the Fd's as unused.
+                */
+               for (i = 0; i < 32; i++) proxy_fds[i] = -1;
+
+               for (listener = mainconfig.listen;
+                    listener != NULL;
+                    listener = listener->next) {
+                       if (listener->type == RAD_LISTEN_PROXY) {
+                               proxy_fds[listener->fd & 0x1f] = listener->fd;
+                               break;
+                       }
+               }
+       }
+
        return 1;
 }
 
@@ -317,12 +345,31 @@ static void rl_delete_proxy(REQUEST *request, rbnode_t *node)
         */
        entry = rbtree_finddata(proxy_id_tree, &myid);
        if (entry) {
+               int i;
+
                DEBUG3(" proxy: de-allocating %08x:%d %d",
                       entry->dst_ipaddr,
                       entry->dst_port,
                       request->proxy->id);
-               rad_assert(entry->id[request->proxy->id] == 1);
-               entry->id[request->proxy->id] = 0;
+
+               /*
+                *      Find the proxy socket associated with this
+                *      Id.  We loop over all 32 proxy fd's, but we
+                *      partially index by proxy fd's, which means
+                *      that we almost always break out of the loop
+                *      quickly.
+                */
+               for (i = 0; i < 32; i++) {
+                       int offset;
+
+                       offset = (request->proxy->sockfd + i) & 0x1f;
+                 
+                       if (proxy_fds[offset] == request->proxy->sockfd) {
+                               
+                               entry->id[request->proxy->id] &= ~(1 << offset);
+                               break;
+                       }
+               } /* else die horribly? */
        } else {
                /*
                 *      Hmm... not sure what to do here.
@@ -504,6 +551,10 @@ REQUEST *rl_find(RADIUS_PACKET *packet)
        return rbtree_finddata(request_tree, &myrequest);
 }
 
+/*
+ *     See mainconfig.c
+ */
+extern int proxy_new_listener(void);
 
 /*
  *     Add an entry to the proxy tree.
@@ -511,9 +562,9 @@ REQUEST *rl_find(RADIUS_PACKET *packet)
  *     This is the ONLY function in this source file which may be called
  *     from a child thread.  It therefore needs mutexes...
  */
-void rl_add_proxy(REQUEST *request)
+int rl_add_proxy(REQUEST *request)
 {
-       int i, found;
+       int             i, found, proxy;
        proxy_id_t      myid, *entry;
 
        myid.dst_ipaddr = request->proxy->dst_ipaddr;
@@ -526,7 +577,6 @@ void rl_add_proxy(REQUEST *request)
         *      code to below, so we can have more than 256 requests
         *      outstanding.
         */
-       request->proxy->sockfd = proxyfd;
        request->proxy_outstanding = 1;
 
        pthread_mutex_lock(&proxy_mutex);
@@ -536,13 +586,14 @@ void rl_add_proxy(REQUEST *request)
         */
        entry = rbtree_finddata(proxy_id_tree, &myid);
        if (!entry) {   /* allocate it */
+               uint32_t mask;
+
                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;
-               memset(entry->id, 0, sizeof(entry->id) * 256);
-               
+
                DEBUG3(" proxy: creating %08x:%d",
                       entry->dst_ipaddr,
                       entry->dst_port);
@@ -556,7 +607,31 @@ void rl_add_proxy(REQUEST *request)
                 *      memory leak.
                 */
                if (rbtree_insert(proxy_id_tree, entry) == 0) {
-                       rad_assert("FAIL" == NULL);
+                       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);
+               mask = ~mask;
+
+               /*
+                *      Set the bits which are unused (and therefore
+                *      allocated).
+                */
+               for (i = 0; i < 256; i++) {
+                       entry->id[i] = mask;
                }
        }
        
@@ -565,7 +640,10 @@ void rl_add_proxy(REQUEST *request)
         */
        found = -1;
        for (i = 0; i < 256; i++) {
-               if (entry->id[(i + entry->index) & 0xff] == 0) {
+               /*
+                *      Some bits are still zero..
+                */
+               if (entry->id[(i + entry->index) & 0xff] != (uint32_t) ~0) {
                        found = (i + entry->index) & 0xff;
                        break;
                }
@@ -576,8 +654,56 @@ void rl_add_proxy(REQUEST *request)
                 */
        }
        
+       /*
+        *      No free Id.  Try to allocate a new proxy FD.
+        */
        if (found < 0) {
-               rad_assert("FAILED TO ALLOCATE ID" == NULL);
+               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;
+                       }
+               }
+
+               /*
+                *      All 32 proxy FD's are allocated.  We can't
+                *      use another one.  Fail.
+                */
+               if (found < 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;
+                              
+               }
+
+
+               /*
+                *      Clear the relevant bits in the mask.
+                */
+               for (i = 0; i < 256; i++) {
+                       entry->id[i] &= ~(1 << found);
+               }
+
+               /*
+                *      Pick a random Id to start from, as we've
+                *      just guaranteed that it's free.
+                */
+               found = lrad_rand() & 0xff;
        }
        
        /*
@@ -585,19 +711,44 @@ void rl_add_proxy(REQUEST *request)
         */
        entry->index = (found + 1) & 0xff;
        
-       entry->id[found] = 1;
+       /*
+        *      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);
+
+       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)) {
-               rad_assert("FAILED" == 0);
+               DEBUG2("ERROR: Failed to insert entry into proxy tree");
+               return 0;
        }
        
        pthread_mutex_unlock(&proxy_mutex);
+
+       return 1;
 }