]> git.vomp.tv Git - vompserver.git/blob - tcp.c
Upgrade to protocol
[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   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 UCHAR* TCP::receivePacket()
129 {
130   if (!connected) return NULL;
131
132   int packetLength;
133   int success;
134
135   success = readData((UCHAR*)&packetLength, sizeof(int));
136   if (!success)
137   {
138     cleanup();
139     return NULL;
140   }
141
142   packetLength = ntohl(packetLength);
143
144   if (packetLength > 200000) return NULL;
145   UCHAR* buffer = (UCHAR*) malloc(packetLength);
146
147   success = readData(buffer, packetLength);
148   if (!success)
149   {
150     cleanup();
151     free(buffer);
152     return NULL;
153   }
154
155 //  dump((unsigned char*)buffer, packetLength);
156
157   dataLength = packetLength;
158   return buffer;
159 }
160
161 int TCP::getDataLength()
162 {
163   return dataLength;
164 }
165
166 int TCP::readData(UCHAR* buffer, int totalBytes)
167 {
168   if (!connected) return 0;
169
170   int bytesRead = 0;
171   int thisRead;
172   int readTries = 0;
173   int success;
174   fd_set readSet;
175   struct timeval timeout;
176   struct timeval* passToSelect;
177
178   if (readTimeoutEnabled) passToSelect = &timeout;
179   else passToSelect = NULL;
180
181   while(1)
182   {
183     FD_ZERO(&readSet);
184     FD_SET(sock, &readSet);
185     timeout.tv_sec = 10;
186     timeout.tv_usec = 0;
187     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
188     if (success < 1)
189     {
190       cleanup();
191       log->log("TCP", Log::DEBUG, "TCP: error or timeout");
192       return 0;  // error, or timeout
193     }
194
195     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
196     if (!thisRead)
197     {
198       // if read returns 0 then connection is closed
199       // in non-blocking mode if read is called with no data available, it returns -1
200       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
201       cleanup();
202       return 0;
203     }
204     bytesRead += thisRead;
205
206 //    log->log("TCP", Log::DEBUG, "Bytes read now: %u", bytesRead);
207     if (bytesRead == totalBytes)
208     {
209       return 1;
210     }
211     else
212     {
213       if (++readTries == 100)
214       {
215         cleanup();
216         log->log("TCP", Log::DEBUG, "too many reads");
217         return 0;
218       }
219     }
220   }
221 }
222
223 int TCP::sendPacket(UCHAR* buf, size_t count)
224 {
225   pthread_mutex_lock(&sendLock);
226   
227   if (!connected)
228   {
229     pthread_mutex_unlock(&sendLock);
230     return 0;
231   }
232
233   unsigned int bytesWritten = 0;
234   int thisWrite;
235   int writeTries = 0;
236   int success;
237   fd_set writeSet;
238   struct timeval timeout;
239
240   while(1)
241   {
242     FD_ZERO(&writeSet);
243     FD_SET(sock, &writeSet);
244     timeout.tv_sec = 10;
245     timeout.tv_usec = 0;
246     success = select(sock + 1, NULL, &writeSet, NULL, &timeout);
247     if (success < 1)
248     {
249       cleanup();
250       log->log("TCP", Log::DEBUG, "TCP: error or timeout");
251       pthread_mutex_unlock(&sendLock);
252       return 0;  // error, or timeout
253     }
254
255     thisWrite = write(sock, &buf[bytesWritten], count - bytesWritten);
256     if (!thisWrite)
257     {
258       // if write returns 0 then connection is closed ?
259       // in non-blocking mode if read is called with no data available, it returns -1
260       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
261       cleanup();
262       log->log("TCP", Log::DEBUG, "Detected connection closed");
263       pthread_mutex_unlock(&sendLock);      
264       return 0;
265     }
266     bytesWritten += thisWrite;
267
268 //    log->log("TCP", Log::DEBUG, "Bytes written now: %u", bytesWritten);
269     if (bytesWritten == count)
270     {
271       pthread_mutex_unlock(&sendLock);
272       return 1;
273     }
274     else
275     {
276       if (++writeTries == 100)
277       {
278         cleanup();
279         log->log("TCP", Log::DEBUG, "too many writes");
280         pthread_mutex_unlock(&sendLock);
281         return 0;
282       }
283     }
284   }
285 }
286
287 void TCP::dump(unsigned char* data, USHORT size)
288 {
289   printf("Size = %u\n", size);
290
291   USHORT c = 0;
292   while(c < size)
293   {
294     if ((size - c) > 15)
295     {
296       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",
297         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
298         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
299         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]),
300         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]));
301       c += 16;
302     }
303     else
304     {
305       switch (size - c)
306       {
307         case 15:
308           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",
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], data[c+14],
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]), dcc(data[c+14]));
313           c += 15;
314           break;
315         case 14:
316           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",
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], data[c+13],
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]), dcc(data[c+13]));
321           c += 14;
322           break;
323         case 13:
324           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",
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], data[c+12],
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]), dcc(data[c+12]));
329           c += 13;
330           break;
331         case 12:
332           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",
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], data[c+11],
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]), dcc(data[c+11]));
337           c += 12;
338           break;
339         case 11:
340           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%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], data[c+10],
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]), dcc(data[c+10]));
345           c += 11;
346           break;
347         case 10:
348           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%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], data[c+9],
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]), dcc(data[c+9]));
353           c += 10;
354           break;
355         case 9:
356           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%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             data[c+8],
359             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]),
360             dcc(data[c+8]));
361           c += 9;
362           break;
363         case 8:
364           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
365             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
366             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]));
367           c += 8;
368           break;
369         case 7:
370           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
371             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
372             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]));
373           c += 7;
374           break;
375         case 6:
376           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
377             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
378             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
379           c += 6;
380           break;
381         case 5:
382           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
383             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
384             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
385           c += 5;
386           break;
387         case 4:
388           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
389             data[c], data[c+1], data[c+2], data[c+3],
390             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
391           c += 4;
392           break;
393         case 3:
394           printf(" %02X %02X %02X                                            %c%c%c\n",
395             data[c], data[c+1], data[c+2],
396             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
397           c += 3;
398           break;
399         case 2:
400           printf(" %02X %02X                                               %c%c\n",
401             data[c], data[c+1],
402             dcc(data[c]), dcc(data[c+1]));
403           c += 2;
404           break;
405         case 1:
406           printf(" %02X                                                  %c\n",
407             data[c],
408             dcc(data[c]));
409           c += 1;
410           break;
411       }
412     }
413   }
414 }
415
416 unsigned char TCP::dcc(UCHAR c)
417 {
418   if (isspace(c)) return ' ';
419   if (isprint(c)) return c;
420   return '.';
421 }