- Added meta.c which contains functions to send, receive and broadcast
[tinc] / src / meta.c
1 /*
2     meta.c -- handle the meta communication
3     Copyright (C) 2000 Guus Sliepen <guus@sliepen.warande.net>,
4                   2000 Ivo Timmermans <itimmermans@bigfoot.com>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: meta.c,v 1.1.2.1 2000/09/26 14:06:03 guus Exp $
21 */
22
23 #include "config.h"
24
25 int send_meta(conn_list_t *cl, const char *buffer, int length)
26 {
27   char outbuf[MAXBUFSIZE];
28   char *bufp;
29 cp
30   if(debug_lvl >= DEBUG_META)
31     syslog(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s): %s"), int length,
32            cl->name, cl->hostname, buffer);
33
34   if(cl->status.encryptout)
35     {
36       if(EVP_EncryptUpdate(cl->cipher_outctx, cl->buffer + cl->buflen, NULL, inbuf, length) != 1)
37         {
38           syslog(LOG_ERR, _("Error during encryption of outgoing metadata to %s (%s)"), cl->name, cl->hostname);
39           return -1;
40         }
41       bufp = outbuf;
42     }
43   else
44     bufp = buffer;
45
46   if(write(cl->meta_socket, bufp, length) < 0)
47     {
48       syslog(LOG_ERR, _("Sending meta data to %s (%s) failed: %m"), cl->name, cl->hostname);
49       return -1;
50     }
51 cp
52   return 0;
53 }
54
55 int broadcast_meta(conn_list_t *cl, const char *buffer, int length)
56 {
57   conn_list_t *p;
58 cp
59   for(p = conn_list; p != NULL; p = p->next)
60     if(p != cl && p->status.meta && p->status.active)
61       send_meta(p, buffer, length);
62 cp
63   return 0;
64 }
65
66 int receive_meta(conn_list_t *cl)
67 {
68   int x, l = sizeof(x);
69   int oldlen, i;
70   int lenin = 0;
71   char inbuf[MAXBUFSIZE];
72   char *bufp;
73 cp
74   if(getsockopt(cl->meta_socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
75     {
76       syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m %s (%s)"), __FILE__, __LINE__, cl->meta_socket,
77              cl->name, cl->hostname);
78       return -1;
79     }
80   if(x)
81     {
82       syslog(LOG_ERR, _("Metadata socket error for %s (%s): %s"),
83              cl->name, cl->hostname, strerror(x));
84       return -1;
85     }
86
87   if(cl->status.encryptin)
88     bufp = inbuf;
89   else
90     bufp = cl->buffer + cl->buflen;
91
92   lenin = read(cl->meta_socket, bufp, MAXBUFSIZE - cl->buflen);
93
94   if(lenin<=0)
95     {
96       if(errno==EINTR)
97         return 0;      
98       if(errno==0)
99         {
100           if(debug_lvl>DEBUG_CONNECTIONS)
101             syslog(LOG_NOTICE, _("Connection closed by %s (%s)"),
102                 cl->name, cl->hostname);
103         }
104       else
105         syslog(LOG_ERR, _("Metadata socket read error for %s (%s): %m"),
106                cl->name, cl->hostname);
107       return -1;
108     }
109
110   if(cl->status.decryptin)
111     {
112       if(EVP_DecryptUpdate(cl->cipher_inctx, cl->buffer + cl->buflen, NULL, inbuf, lenin) != 1)
113         {
114           syslog(LOG_ERR, _("Error during decryption of incoming metadata from %s (%s)"), cl->name, cl->hostname);
115           return -1;
116         }
117     }
118     
119   oldlen = cl->buflen;
120   cl->buflen += lenin;
121
122   for(;;)
123     {
124       cl->reqlen = 0;
125
126       for(i = oldlen; i < cl->buflen; i++)
127         {
128           if(cl->buffer[i] == '\n')
129             {
130               cl->buffer[i] = 0;  /* replace end-of-line by end-of-string so we can use sscanf */
131               cl->reqlen = i + 1;
132               break;
133             }
134         }
135
136       if(cl->reqlen)
137         {
138           if(debug_lvl > DEBUG_META)
139             syslog(LOG_DEBUG, _("Got request from %s (%s): %s"),
140                    cl->name, cl->hostname, cl->buffer);
141
142           if(receive_request(cl))
143             return -1;
144
145           cl->buflen -= cl->reqlen;
146           memmove(cl->buffer, cl->buffer + cl->reqlen, cl->buflen);
147           oldlen = 0;
148         }
149       else
150         {
151           break;
152         }
153     }
154
155   if(cl->buflen >= MAXBUFSIZE)
156     {
157       syslog(LOG_ERR, _("Metadata read buffer overflow for %s (%s)"),
158              cl->name, cl->hostname);
159       return -1;
160     }
161
162   cl->last_ping_time = time(NULL);
163   cl->want_ping = 0;
164 cp  
165   return 0;
166 }