X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=tcp.c;h=8d559414e591a40f5a87d47140e45e82fbd622c7;hb=c1f196080a7cb867afd3dee50e2910899cbf5f46;hp=24d75aefca2312ff7698b719bf86d0f226083a9b;hpb=a710bc2df1fbb8c1e967a27dbcbf325b19014208;p=libradsec.git diff --git a/tcp.c b/tcp.c index 24d75ae..8d55941 100644 --- a/tcp.c +++ b/tcp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Stig Venaas + * Copyright (C) 2008-2009 Stig Venaas * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,17 +24,68 @@ #include #include #include -#include -#include "debug.h" #include "list.h" -#include "util.h" +#include "hostport.h" #include "radsecproxy.h" -#include "tcp.h" + +#ifdef RADPROT_TCP +#include "debug.h" +#include "util.h" +static void setprotoopts(struct commonprotoopts *opts); +static char **getlistenerargs(); +void *tcplistener(void *arg); +int tcpconnect(struct server *server, struct timeval *when, int timeout, char * text); +void *tcpclientrd(void *arg); +int clientradputtcp(struct server *server, unsigned char *rad); +void tcpsetsrcres(); + +static const struct protodefs protodefs = { + "tcp", + NULL, /* secretdefault */ + SOCK_STREAM, /* socktype */ + "1812", /* portdefault */ + 0, /* retrycountdefault */ + 0, /* retrycountmax */ + REQUEST_RETRY_INTERVAL * REQUEST_RETRY_COUNT, /* retryintervaldefault */ + 60, /* retryintervalmax */ + DUPLICATE_INTERVAL, /* duplicateintervaldefault */ + setprotoopts, /* setprotoopts */ + getlistenerargs, /* getlistenerargs */ + tcplistener, /* listener */ + tcpconnect, /* connecter */ + tcpclientrd, /* clientconnreader */ + clientradputtcp, /* clientradput */ + NULL, /* addclient */ + NULL, /* addserverextra */ + tcpsetsrcres, /* setsrcres */ + NULL /* initextra */ +}; + +static struct addrinfo *srcres = NULL; +static uint8_t handle; +static struct commonprotoopts *protoopts = NULL; +const struct protodefs *tcpinit(uint8_t h) { + handle = h; + return &protodefs; +} + +static void setprotoopts(struct commonprotoopts *opts) { + protoopts = opts; +} + +static char **getlistenerargs() { + return protoopts ? protoopts->listenargs : NULL; +} + +void tcpsetsrcres() { + if (!srcres) + srcres = resolvepassiveaddrinfo(protoopts ? protoopts->sourcearg : NULL, NULL, protodefs.socktype); +} int tcpconnect(struct server *server, struct timeval *when, int timeout, char *text) { struct timeval now; time_t elapsed; - + debug(DBG_DBG, "tcpconnect: called from %s", text); pthread_mutex_lock(&server->lock); if (when && memcmp(&server->lastconnecttry, when, sizeof(struct timeval))) { @@ -67,14 +118,13 @@ int tcpconnect(struct server *server, struct timeval *when, int timeout, char *t sleep(60); } else server->lastconnecttry.tv_sec = now.tv_sec; /* no sleep at startup */ - debug(DBG_WARN, "tcpconnect: trying to open TCP connection to %s port %s", server->conf->host, server->conf->port); + if (server->sock >= 0) close(server->sock); - if ((server->sock = connecttcp(server->conf->addrinfo, getsrcprotores(RAD_TCP))) >= 0) + if ((server->sock = connecttcphostlist(server->conf->hostports, srcres)) >= 0) break; - debug(DBG_ERR, "tcpconnect: connecttcp failed"); } - debug(DBG_WARN, "tcpconnect: TCP connection to %s port %s up", server->conf->host, server->conf->port); + server->connectionok = 1; gettimeofday(&server->lastconnecttry, NULL); pthread_mutex_unlock(&server->lock); return 1; @@ -86,7 +136,7 @@ int tcpreadtimeout(int s, unsigned char *buf, int num, int timeout) { int ndesc, cnt, len; fd_set readfds, writefds; struct timeval timer; - + if (s < 0) return -1; /* make socket non-blocking? */ @@ -128,21 +178,21 @@ unsigned char *radtcpget(int s, int timeout) { continue; } memcpy(rad, buf, 4); - + cnt = tcpreadtimeout(s, rad + 4, len - 4, timeout); if (cnt < 1) { debug(DBG_DBG, cnt ? "radtcpget: connection lost" : "radtcpget: timeout"); free(rad); return NULL; } - + if (len >= 20) break; - + free(rad); debug(DBG_WARN, "radtcpget: packet smaller than minimum radius size"); } - + debug(DBG_DBG, "radtcpget: got %d bytes", len); return rad; } @@ -150,19 +200,16 @@ unsigned char *radtcpget(int s, int timeout) { int clientradputtcp(struct server *server, unsigned char *rad) { int cnt; size_t len; - struct timeval lastconnecttry; struct clsrvconf *conf = server->conf; - + + if (!server->connectionok) + return 0; len = RADLEN(rad); - lastconnecttry = server->lastconnecttry; - while ((cnt = write(server->sock, rad, len)) <= 0) { + if ((cnt = write(server->sock, rad, len)) <= 0) { debug(DBG_ERR, "clientradputtcp: write error"); - tcpconnect(server, &lastconnecttry, 0, "clientradputtcp"); - lastconnecttry = server->lastconnecttry; + return 0; } - - server->connectionok = 1; - debug(DBG_DBG, "clientradputtcp: Sent %d bytes, Radius packet of length %d to TCP peer %s", cnt, len, conf->host); + debug(DBG_DBG, "clientradputtcp: Sent %d bytes, Radius packet of length %d to TCP peer %s", cnt, len, conf->name); return 1; } @@ -170,7 +217,7 @@ void *tcpclientrd(void *arg) { struct server *server = (struct server *)arg; unsigned char *buf; struct timeval lastconnecttry; - + for (;;) { /* yes, lastconnecttry is really necessary */ lastconnecttry = server->lastconnecttry; @@ -189,15 +236,15 @@ void *tcpclientrd(void *arg) { void *tcpserverwr(void *arg) { int cnt; struct client *client = (struct client *)arg; - struct queue *replyq; + struct gqueue *replyq; struct request *reply; - - debug(DBG_DBG, "tcpserverwr: starting for %s", client->conf->host); + + debug(DBG_DBG, "tcpserverwr: starting for %s", addr2string(client->addr)); replyq = client->replyq; for (;;) { pthread_mutex_lock(&replyq->mutex); while (!list_first(replyq->entries)) { - if (client->sock >= 0) { + if (client->sock >= 0) { debug(DBG_DBG, "tcpserverwr: waiting for signal"); pthread_cond_wait(&replyq->cond, &replyq->mutex); debug(DBG_DBG, "tcpserverwr: got signal"); @@ -213,10 +260,10 @@ void *tcpserverwr(void *arg) { pthread_mutex_unlock(&replyq->mutex); cnt = write(client->sock, reply->replybuf, RADLEN(reply->replybuf)); if (cnt > 0) - debug(DBG_DBG, "tcpserverwr: sent %d bytes, Radius packet of length %d", - cnt, RADLEN(reply->replybuf)); + debug(DBG_DBG, "tcpserverwr: sent %d bytes, Radius packet of length %d to %s", + cnt, RADLEN(reply->replybuf), addr2string(client->addr)); else - debug(DBG_ERR, "tcpserverwr: write error for %s", client->conf->host); + debug(DBG_ERR, "tcpserverwr: write error for %s", addr2string(client->addr)); freerq(reply); } } @@ -225,9 +272,9 @@ void tcpserverrd(struct client *client) { struct request *rq; uint8_t *buf; pthread_t tcpserverwrth; - - debug(DBG_DBG, "tcpserverrd: starting for %s", client->conf->host); - + + debug(DBG_DBG, "tcpserverrd: starting for %s", addr2string(client->addr)); + if (pthread_create(&tcpserverwrth, NULL, tcpserverwr, (void *)client)) { debug(DBG_ERR, "tcpserverrd: pthread_create failed"); return; @@ -236,10 +283,10 @@ void tcpserverrd(struct client *client) { for (;;) { buf = radtcpget(client->sock, 0); if (!buf) { - debug(DBG_ERR, "tcpserverrd: connection from %s lost", client->conf->host); + debug(DBG_ERR, "tcpserverrd: connection from %s lost", addr2string(client->addr)); break; } - debug(DBG_DBG, "tcpserverrd: got Radius message from %s", client->conf->host); + debug(DBG_DBG, "tcpserverrd: got Radius message from %s", addr2string(client->addr)); rq = newrequest(); if (!rq) { free(buf); @@ -248,7 +295,7 @@ void tcpserverrd(struct client *client) { rq->buf = buf; rq->from = client; if (!radsrv(rq)) { - debug(DBG_ERR, "tcpserverrd: message authentication/validation failed, closing connection from %s", client->conf->host); + debug(DBG_ERR, "tcpserverrd: message authentication/validation failed, closing connection from %s", addr2string(client->addr)); break; } } @@ -260,14 +307,12 @@ void tcpserverrd(struct client *client) { pthread_mutex_unlock(&client->replyq->mutex); debug(DBG_DBG, "tcpserverrd: waiting for writer to end"); pthread_join(tcpserverwrth, NULL); - removeclientrqs(client); - debug(DBG_DBG, "tcpserverrd: reader for %s exiting", client->conf->host); + debug(DBG_DBG, "tcpserverrd: reader for %s exiting", addr2string(client->addr)); } - void *tcpservernew(void *arg) { int s; struct sockaddr_storage from; - size_t fromlen = sizeof(from); + socklen_t fromlen = sizeof(from); struct clsrvconf *conf; struct client *client; @@ -276,13 +321,14 @@ void *tcpservernew(void *arg) { debug(DBG_DBG, "tcpservernew: getpeername failed, exiting"); goto exit; } - debug(DBG_WARN, "tcpservernew: incoming TCP connection from %s", addr2string((struct sockaddr *)&from, fromlen)); + debug(DBG_WARN, "tcpservernew: incoming TCP connection from %s", addr2string((struct sockaddr *)&from)); - conf = find_clconf(RAD_TCP, (struct sockaddr *)&from, NULL); + conf = find_clconf(handle, (struct sockaddr *)&from, NULL); if (conf) { client = addclient(conf, 1); if (client) { client->sock = s; + client->addr = addr_copy((struct sockaddr *)&from); tcpserverrd(client); removeclient(client); } else @@ -290,7 +336,7 @@ void *tcpservernew(void *arg) { } else debug(DBG_WARN, "tcpservernew: ignoring request, no matching TCP client"); - exit: +exit: shutdown(s, SHUT_RDWR); close(s); pthread_exit(NULL); @@ -300,7 +346,7 @@ void *tcplistener(void *arg) { pthread_t tcpserverth; int s, *sp = (int *)arg; struct sockaddr_storage from; - size_t fromlen = sizeof(from); + socklen_t fromlen = sizeof(from); listen(*sp, 0); @@ -321,3 +367,12 @@ void *tcplistener(void *arg) { free(sp); return NULL; } +#else +const struct protodefs *tcpinit(uint8_t h) { + return NULL; +} +#endif + +/* Local Variables: */ +/* c-file-style: "stroustrup" */ +/* End: */