diff options
| author | venaas <venaas> | 2008-09-30 14:40:17 +0000 | 
|---|---|---|
| committer | venaas <venaas@e88ac4ed-0b26-0410-9574-a7f39faa03bf> | 2008-09-30 14:40:17 +0000 | 
| commit | ce2faa29b9e921d11e93b54a98dee687d4a861b4 (patch) | |
| tree | 9e965c605fcdd4cf993c40b5a77cf7840d8f473f | |
| parent | 9059151dbb4dbda7f7d4f1a96a7d0b8db5756a0a (diff) | |
expiry of udp clients
git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@412 e88ac4ed-0b26-0410-9574-a7f39faa03bf
| -rw-r--r-- | radsecproxy.c | 19 | ||||
| -rw-r--r-- | radsecproxy.h | 2 | ||||
| -rw-r--r-- | udp.c | 55 | 
3 files changed, 60 insertions, 16 deletions
| diff --git a/radsecproxy.c b/radsecproxy.c index 533bf90..b89577a 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -36,7 +36,6 @@  /* Bugs:   * May segfault when dtls connections go down? More testing needed - * Need to remove UDP clients when no activity for a while...   * Remove expired stuff from clients request list?   * Multiple outgoing connections if not enough IDs? (multiple servers per conf?)   * Useful for TCP accounting? Now we require separate server config for alt port @@ -574,13 +573,10 @@ void removeclientrqs(struct client *client) {      removeclientrqs_sendrq_freeserver_lock(0);  } -void removeclient(struct client *client) { +void removelockedclient(struct client *client) {      struct clsrvconf *conf; -    if (!client) -	return;      conf = client->conf; -    pthread_mutex_lock(conf->lock);      if (conf->clients) {  	removeclientrqs(client);  	removequeue(client->replyq); @@ -588,6 +584,17 @@ void removeclient(struct client *client) {  	free(client->addr);  	free(client);      } +} + +void removeclient(struct client *client) { +    struct clsrvconf *conf; +     +    if (!client) +	return; + +    conf = client->conf; +    pthread_mutex_lock(conf->lock); +    removelockedclient(client);      pthread_mutex_unlock(conf->lock);  } @@ -2037,7 +2044,7 @@ void replyh(struct server *server, unsigned char *buf) {  	goto errunlock;      } -    debug(DBG_INFO, "replyh: passing reply to client %s", from->conf->name); +    debug(DBG_INFO, "replyh: passing reply to client %s (%s)", from->conf->name, addr2string(from->addr));      radmsg_free(rqout->rq->msg);      rqout->rq->msg = msg;      sendreply(newrqref(rqout->rq)); diff --git a/radsecproxy.h b/radsecproxy.h index 4be2274..520703f 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -110,6 +110,7 @@ struct client {      struct queue *replyq;      struct queue *rbios; /* for dtls */      struct sockaddr *addr; +    time_t expiry; /* for udp */  };  struct server { @@ -206,6 +207,7 @@ struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_n  struct clsrvconf *find_srvconf(uint8_t type, struct sockaddr *addr, struct list_node **cur);  struct clsrvconf *find_clconf_type(uint8_t type, struct list_node **cur);  struct client *addclient(struct clsrvconf *conf, uint8_t lock); +void removelockedclient(struct client *client);  void removeclient(struct client *client);  struct queue *newqueue();  void freebios(struct queue *q); @@ -35,6 +35,20 @@ static int client4_sock = -1;  static int client6_sock = -1;  static struct queue *server_replyq = NULL; +void removeudpclientfromreplyq(struct client *c) { +    struct list_node *n; +    struct request *r; +     +    /* lock the common queue and remove replies for this client */ +    pthread_mutex_lock(&c->replyq->mutex); +    for (n = list_first(c->replyq->entries); n; n = list_next(n)) { +	r = (struct request *)n->data; +	if (r->from == c) +	    r->from = NULL; +    } +    pthread_mutex_unlock(&c->replyq->mutex); +}	 +  /* exactly one of client and server must be non-NULL */  /* return who we received from in *client or *server */  /* return from in sa if not NULL */ @@ -48,6 +62,7 @@ unsigned char *radudpget(int s, struct client **client, struct server **server,      struct list_node *node;      fd_set readfds;      struct client *c = NULL; +    struct timeval now;      for (;;) {  	if (rad) { @@ -103,13 +118,28 @@ unsigned char *radudpget(int s, struct client **client, struct server **server,  	    debug(DBG_DBG, "radudpget: packet was padded with %d bytes", cnt - len);  	if (client) { +	    *client = NULL;  	    pthread_mutex_lock(p->lock); -	    for (node = list_first(p->clients); node; node = list_next(node)) { +	    for (node = list_first(p->clients); node;) {  		c = (struct client *)node->data; -		if (s == c->sock && addr_equal((struct sockaddr *)&from, c->addr)) -		    break; +		node = list_next(node); +		if (s != c->sock) +		    continue; +		gettimeofday(&now, NULL); +		if (!*client && addr_equal((struct sockaddr *)&from, c->addr)) { +		    c->expiry = now.tv_sec + 60; +		    *client = c; +		} +		if (c->expiry >= now.tv_sec) +		    continue; +		 +		debug(DBG_DBG, "radudpget: removing expired client (%s)", addr2string(c->addr)); +		removeudpclientfromreplyq(c); +		c->replyq = NULL; /* stop removeclient() from removing common udp replyq */ +		removelockedclient(c); +		break;  	    } -	    if (!node) { +	    if (!*client) {  		fromcopy = addr_copy((struct sockaddr *)&from);  		if (!fromcopy) {  		    pthread_mutex_unlock(p->lock); @@ -123,8 +153,10 @@ unsigned char *radudpget(int s, struct client **client, struct server **server,  		}  		c->sock = s;  		c->addr = fromcopy; +		gettimeofday(&now, NULL); +		c->expiry = now.tv_sec + 60; +		*client = c;  	    } -	    *client = c;  	    pthread_mutex_unlock(p->lock);  	} else if (server)  	    *server = p->servers; @@ -202,12 +234,15 @@ void *udpserverwr(void *arg) {  	    pthread_cond_wait(&replyq->cond, &replyq->mutex);  	    debug(DBG_DBG, "udp server writer, got signal");  	} +	/* do this with lock, udpserverrd may set from = NULL if from expires */ +	if (reply->from) +	    memcpy(&to, reply->from->addr, SOCKADDRP_SIZE(reply->from->addr));  	pthread_mutex_unlock(&replyq->mutex); - -	memcpy(&to, reply->from->addr, SOCKADDRP_SIZE(reply->from->addr)); -	port_set((struct sockaddr *)&to, reply->udpport); -	if (sendto(reply->udpsock, reply->replybuf, RADLEN(reply->replybuf), 0, (struct sockaddr *)&to, SOCKADDR_SIZE(to)) < 0) -	    debug(DBG_WARN, "udpserverwr: send failed"); +	if (reply->from) { +	    port_set((struct sockaddr *)&to, reply->udpport); +	    if (sendto(reply->udpsock, reply->replybuf, RADLEN(reply->replybuf), 0, (struct sockaddr *)&to, SOCKADDR_SIZE(to)) < 0) +		debug(DBG_WARN, "udpserverwr: send failed"); +	}  	debug(DBG_DBG, "udpserverwr: refcount %d", reply->refcount);  	freerq(reply);      } | 
