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