X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fmeta.c;h=c3d4f82906614c47c4a6223407ced76c3d5728d0;hp=31a387a07a31931599b3cbab0306c830989051aa;hb=8b2b67e26c5b971761f5015764d5e188f6343bc4;hpb=52b842f8076d507d3a6ea07045d085ae21d1aa10 diff --git a/src/meta.c b/src/meta.c index 31a387a0..c3d4f829 100644 --- a/src/meta.c +++ b/src/meta.c @@ -1,7 +1,7 @@ /* meta.c -- handle the meta communication - Copyright (C) 2000 Guus Sliepen , - 2000 Ivo Timmermans + Copyright (C) 2000-2002 Guus Sliepen , + 2000-2002 Ivo Timmermans This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,139 +17,180 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: meta.c,v 1.1.2.5 2000/10/21 11:52:06 guus Exp $ + $Id: meta.c,v 1.1.2.27 2002/09/04 16:26:44 guus Exp $ */ #include "config.h" #include +#include #include #include -#include +#include +#include +/* This line must be below the rest for FreeBSD */ +#include #include + #include #include "net.h" +#include "connection.h" #include "system.h" +#include "protocol.h" -int send_meta(conn_list_t *cl, char *buffer, int length) +int send_meta(connection_t *c, char *buffer, int length) { - char outbuf[MAXBUFSIZE]; char *bufp; int outlen; + char outbuf[MAXBUFSIZE]; cp if(debug_lvl >= DEBUG_META) - syslog(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s): %s"), length, - cl->name, cl->hostname, buffer); + syslog(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s)"), length, + c->name, c->hostname); - buffer[length-1]='\n'; - - if(cl->status.encryptout) + if(c->status.encryptout) { - EVP_EncryptUpdate(cl->cipher_outctx, outbuf, &outlen, buffer, length); + EVP_EncryptUpdate(c->outctx, outbuf, &outlen, buffer, length); bufp = outbuf; + length = outlen; } else - bufp = buffer; + bufp = buffer; - if(write(cl->meta_socket, bufp, length) < 0) + if(write(c->socket, bufp, length) < 0) { - syslog(LOG_ERR, _("Sending meta data to %s (%s) failed: %m"), cl->name, cl->hostname); + syslog(LOG_ERR, _("Sending meta data to %s (%s) failed: %s"), c->name, c->hostname, strerror(errno)); return -1; } cp return 0; } -int broadcast_meta(conn_list_t *cl, char *buffer, int length) +void broadcast_meta(connection_t *from, char *buffer, int length) { - conn_list_t *p; + avl_node_t *node; + connection_t *c; cp - for(p = conn_list; p != NULL; p = p->next) - if(p != cl && p->status.meta && p->status.active) - send_meta(p, buffer, length); + for(node = connection_tree->head; node; node = node->next) + { + c = (connection_t *)node->data; + if(c != from && c->status.active) + send_meta(c, buffer, length); + } cp - return 0; } -int receive_meta(conn_list_t *cl) +int receive_meta(connection_t *c) { int x, l = sizeof(x); int oldlen, i; - int lenin = 0; + int lenin, reqlen; + int decrypted = 0; char inbuf[MAXBUFSIZE]; - char *bufp; cp - if(getsockopt(cl->meta_socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0) + if(getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0) { - syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m %s (%s)"), __FILE__, __LINE__, cl->meta_socket, - cl->name, cl->hostname); + syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%s %s (%s)"), __FILE__, __LINE__, c->socket, strerror(errno), + c->name, c->hostname); return -1; } if(x) { syslog(LOG_ERR, _("Metadata socket error for %s (%s): %s"), - cl->name, cl->hostname, strerror(x)); + c->name, c->hostname, strerror(x)); return -1; } - if(cl->status.decryptin) - bufp = inbuf; - else - bufp = cl->buffer + cl->buflen; + /* Strategy: + - Read as much as possible from the TCP socket in one go. + - Decrypt it. + - Check if a full request is in the input buffer. + - If yes, process request and remove it from the buffer, + then check again. + - If not, keep stuff in buffer and exit. + */ - lenin = read(cl->meta_socket, bufp, MAXBUFSIZE - cl->buflen); + lenin = read(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen); if(lenin<=0) { - if(errno==EINTR) - return 0; - if(errno==0) + if(lenin==0) { if(debug_lvl >= DEBUG_CONNECTIONS) syslog(LOG_NOTICE, _("Connection closed by %s (%s)"), - cl->name, cl->hostname); + c->name, c->hostname); } else - syslog(LOG_ERR, _("Metadata socket read error for %s (%s): %m"), - cl->name, cl->hostname); + if(errno==EINTR) + return 0; + else + syslog(LOG_ERR, _("Metadata socket read error for %s (%s): %s"), + c->name, c->hostname, strerror(errno)); + return -1; } - if(cl->status.decryptin) - { - EVP_DecryptUpdate(cl->cipher_inctx, cl->buffer + cl->buflen, NULL, inbuf, lenin); - } - - oldlen = cl->buflen; - cl->buflen += lenin; + oldlen = c->buflen; + c->buflen += lenin; - for(;;) + while(lenin) { - cl->reqlen = 0; + /* Decrypt */ + + if(c->status.decryptin && !decrypted) + { + EVP_DecryptUpdate(c->inctx, inbuf, &lenin, c->buffer + oldlen, lenin); + memcpy(c->buffer + oldlen, inbuf, lenin); + decrypted = 1; + } + + /* Are we receiving a TCPpacket? */ - for(i = oldlen; i < cl->buflen; i++) + if(c->tcplen) { - if(cl->buffer[i] == '\n') + if(c->tcplen <= c->buflen) + { + receive_tcppacket(c, c->buffer, c->tcplen); + + c->buflen -= c->tcplen; + lenin -= c->tcplen; + memmove(c->buffer, c->buffer + c->tcplen, c->buflen); + oldlen = 0; + c->tcplen = 0; + continue; + } + else { - cl->buffer[i] = 0; /* replace end-of-line by end-of-string so we can use sscanf */ - cl->reqlen = i + 1; break; } } - if(cl->reqlen) + /* Otherwise we are waiting for a request */ + + reqlen = 0; + + for(i = oldlen; i < c->buflen; i++) { - if(debug_lvl >= DEBUG_PROTOCOL) - syslog(LOG_DEBUG, _("Got request from %s (%s): %s"), - cl->name, cl->hostname, cl->buffer); + if(c->buffer[i] == '\n') + { + c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */ + reqlen = i + 1; + break; + } + } - if(receive_request(cl)) + if(reqlen) + { + c->reqlen = reqlen; + if(receive_request(c)) return -1; - cl->buflen -= cl->reqlen; - memmove(cl->buffer, cl->buffer + cl->reqlen, cl->buflen); + c->buflen -= reqlen; + lenin -= reqlen; + memmove(c->buffer, c->buffer + reqlen, c->buflen); oldlen = 0; + continue; } else { @@ -157,15 +198,14 @@ cp } } - if(cl->buflen >= MAXBUFSIZE) + if(c->buflen >= MAXBUFSIZE) { syslog(LOG_ERR, _("Metadata read buffer overflow for %s (%s)"), - cl->name, cl->hostname); + c->name, c->hostname); return -1; } - cl->last_ping_time = time(NULL); - cl->want_ping = 0; + c->last_ping_time = now; cp return 0; }