]> git.vomp.tv Git - vompserver.git/blob - tcp.c
New logging system
[vompserver.git] / tcp.c
1 /*
2     Copyright 2004-2005 Chris Tallon
3     Copyright 2003-2004 University Of Bradford
4
5     This file is part of VOMP.
6
7     VOMP is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     VOMP is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with VOMP; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22 #include "tcp.h"
23
24 TCP::TCP(int tsocket)
25 {
26   log = Log::getInstance();
27   sock = -1;
28   connected = 0;
29   readTimeoutEnabled = 1;
30
31   if (tsocket)
32   {
33     sock = tsocket;
34     connected = 1;
35   }
36 }
37
38 TCP::~TCP()
39 {
40   if (connected) cleanup();
41 }
42
43 void TCP::cleanup()
44 {
45   close(sock);
46   sock = -1;
47   connected = 0;
48   log->log("TCP", Log::DEBUG, "TCP has closed socket");
49 }
50
51
52 void TCP::disableReadTimeout()
53 {
54   readTimeoutEnabled = 0;
55 }
56
57 int TCP::connectTo(char* host, unsigned short port)
58 {
59   sock = socket(PF_INET, SOCK_STREAM, 0);
60   if (sock == -1) return 0;
61
62   struct sockaddr_in dest_addr;
63   dest_addr.sin_family = AF_INET;
64   dest_addr.sin_port = htons(port);
65
66   if (!inet_aton(host, &dest_addr.sin_addr))
67   {
68     cleanup();
69     return 0;
70   }
71
72   memset(&(dest_addr.sin_zero), '\0', 8);
73
74   int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
75   if (success == -1)
76   {
77     cleanup();
78     return 0;
79   }
80
81   connected = 1;
82   return 1;
83 }
84
85 void TCP::setNonBlocking()
86 {
87   int oldflags = fcntl(sock, F_GETFL, 0);
88   oldflags |= O_NONBLOCK;
89   fcntl(sock, F_SETFL, oldflags);
90 }
91
92 int TCP::setSoKeepTime(int timeOut)
93 {
94   int option;
95   int s1, s2, s3, s4;
96
97   option = 1;
98   s1 = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option));
99   log->log("TCP", Log::DEBUG, "SO_KEEPALIVE = %i", s1);
100
101   option = timeOut;
102   s2 = setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &option, sizeof(option));
103   log->log("TCP", Log::DEBUG, "TCP_KEEPIDLE = %i", s2);
104
105   s3 = setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &option, sizeof(option));
106   log->log("TCP", Log::DEBUG, "TCP_KEEPINTVL = %i", s3);
107
108   option = 2;
109   s4 = setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &option, sizeof(option));
110   log->log("TCP", Log::DEBUG, "TCP_KEEPCNT = %i", s4);
111
112   if (s1 || s2 || s3 || s4) return 0;
113   return 1;
114 }
115
116 void TCP::assignSocket(int tsocket)
117 {
118   sock = tsocket;
119   connected = 1;
120 }
121
122 int TCP::isConnected()
123 {
124   return connected;
125 }
126
127 UCHAR* TCP::receivePacket()
128 {
129   if (!connected) return NULL;
130
131   int packetLength;
132   int success;
133
134   success = readData((UCHAR*)&packetLength, sizeof(int));
135   if (!success)
136   {
137     cleanup();
138     return NULL;
139   }
140
141   packetLength = ntohl(packetLength);
142
143   if (packetLength > 200000) return NULL;
144   UCHAR* buffer = (UCHAR*) malloc(packetLength);
145
146   success = readData(buffer, packetLength);
147   if (!success)
148   {
149     cleanup();
150     free(buffer);
151     return NULL;
152   }
153
154 //  dump((unsigned char*)buffer, packetLength);
155
156   dataLength = packetLength;
157   return buffer;
158 }
159
160 int TCP::getDataLength()
161 {
162   return dataLength;
163 }
164
165 int TCP::readData(UCHAR* buffer, int totalBytes)
166 {
167   if (!connected) return 0;
168
169   int bytesRead = 0;
170   int thisRead;
171   int readTries = 0;
172   int success;
173   fd_set readSet;
174   struct timeval timeout;
175   struct timeval* passToSelect;
176
177   if (readTimeoutEnabled) passToSelect = &timeout;
178   else passToSelect = NULL;
179
180   while(1)
181   {
182     FD_ZERO(&readSet);
183     FD_SET(sock, &readSet);
184     timeout.tv_sec = 10;
185     timeout.tv_usec = 0;
186     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
187     if (success < 1)
188     {
189       cleanup();
190       log->log("TCP", Log::DEBUG, "TCP: error or timeout");
191       return 0;  // error, or timeout
192     }
193
194     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
195     if (!thisRead)
196     {
197       // if read returns 0 then connection is closed
198       // in non-blocking mode if read is called with no data available, it returns -1
199       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
200       cleanup();
201       return 0;
202     }
203     bytesRead += thisRead;
204
205 //    log->log("TCP", Log::DEBUG, "Bytes read now: %u", bytesRead);
206     if (bytesRead == totalBytes)
207     {
208       return 1;
209     }
210     else
211     {
212       if (++readTries == 100)
213       {
214         cleanup();
215         log->log("TCP", Log::DEBUG, "too many reads");
216         return 0;
217       }
218     }
219   }
220 }
221
222 int TCP::sendPacket(UCHAR* buf, size_t count)
223 {
224   if (!connected) return 0;
225
226   unsigned int bytesWritten = 0;
227   int thisWrite;
228   int writeTries = 0;
229   int success;
230   fd_set writeSet;
231   struct timeval timeout;
232
233   while(1)
234   {
235     FD_ZERO(&writeSet);
236     FD_SET(sock, &writeSet);
237     timeout.tv_sec = 10;
238     timeout.tv_usec = 0;
239     success = select(sock + 1, NULL, &writeSet, NULL, &timeout);
240     if (success < 1)
241     {
242       cleanup();
243       log->log("TCP", Log::DEBUG, "TCP: error or timeout");
244       return 0;  // error, or timeout
245     }
246
247     thisWrite = write(sock, &buf[bytesWritten], count - bytesWritten);
248     if (!thisWrite)
249     {
250       // if write returns 0 then connection is closed ?
251       // in non-blocking mode if read is called with no data available, it returns -1
252       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
253       cleanup();
254       log->log("TCP", Log::DEBUG, "Detected connection closed");
255       return 0;
256     }
257     bytesWritten += thisWrite;
258
259 //    log->log("TCP", Log::DEBUG, "Bytes written now: %u", bytesWritten);
260     if (bytesWritten == count)
261     {
262       return 1;
263     }
264     else
265     {
266       if (++writeTries == 100)
267       {
268         cleanup();
269         log->log("TCP", Log::DEBUG, "too many writes");
270         return 0;
271       }
272     }
273   }
274 }
275
276
277
278
279 void TCP::dump(unsigned char* data, USHORT size)
280 {
281   printf("Size = %u\n", size);
282
283   USHORT c = 0;
284   while(c < size)
285   {
286     if ((size - c) > 15)
287     {
288       printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
289         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
290         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
291         dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
292         dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]), dcc(data[c+15]));
293       c += 16;
294     }
295     else
296     {
297       switch (size - c)
298       {
299         case 15:
300           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X     %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
301             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
302             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
303             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
304             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]));
305           c += 15;
306           break;
307         case 14:
308           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X        %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
309             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
310             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
311             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
312             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
313           c += 14;
314           break;
315         case 13:
316           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X           %c%c%c%c%c%c%c%c%c%c%c%c%c\n",
317             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
318             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
319             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
320             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
321           c += 13;
322           break;
323         case 12:
324           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X               %c%c%c%c%c%c%c%c%c%c%c%c\n",
325             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
326             data[c+8], data[c+9], data[c+10], data[c+11],
327             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
328             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
329           c += 12;
330           break;
331         case 11:
332           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
333             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
334             data[c+8], data[c+9], data[c+10],
335             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
336             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
337           c += 11;
338           break;
339         case 10:
340           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
341             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
342             data[c+8], data[c+9],
343             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
344             dcc(data[c+8]), dcc(data[c+9]));
345           c += 10;
346           break;
347         case 9:
348           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
349             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
350             data[c+8],
351             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
352             dcc(data[c+8]));
353           c += 9;
354           break;
355         case 8:
356           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
357             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
358             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]));
359           c += 8;
360           break;
361         case 7:
362           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
363             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
364             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]));
365           c += 7;
366           break;
367         case 6:
368           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
369             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
370             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
371           c += 6;
372           break;
373         case 5:
374           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
375             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
376             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
377           c += 5;
378           break;
379         case 4:
380           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
381             data[c], data[c+1], data[c+2], data[c+3],
382             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
383           c += 4;
384           break;
385         case 3:
386           printf(" %02X %02X %02X                                            %c%c%c\n",
387             data[c], data[c+1], data[c+2],
388             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
389           c += 3;
390           break;
391         case 2:
392           printf(" %02X %02X                                               %c%c\n",
393             data[c], data[c+1],
394             dcc(data[c]), dcc(data[c+1]));
395           c += 2;
396           break;
397         case 1:
398           printf(" %02X                                                  %c\n",
399             data[c],
400             dcc(data[c]));
401           c += 1;
402           break;
403       }
404     }
405   }
406 }
407
408 unsigned char TCP::dcc(UCHAR c)
409 {
410   if (isspace(c)) return ' ';
411   if (isprint(c)) return c;
412   return '.';
413 }