]> git.vomp.tv Git - vompserver.git/blob - tcp.c
*** empty log message ***
[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           log->log("TCP", Log::DEBUG, "written %i", thisWrite);
257     if (!thisWrite)
258     {
259       // if write returns 0 then connection is closed ?
260       // in non-blocking mode if read is called with no data available, it returns -1
261       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
262       cleanup();
263       log->log("TCP", Log::DEBUG, "Detected connection closed");
264       pthread_mutex_unlock(&sendLock);      
265       return 0;
266     }
267     bytesWritten += thisWrite;
268
269 //    log->log("TCP", Log::DEBUG, "Bytes written now: %u", bytesWritten);
270     if (bytesWritten == count)
271     {
272       pthread_mutex_unlock(&sendLock);
273       return 1;
274     }
275     else
276     {
277       if (++writeTries == 100)
278       {
279         cleanup();
280         log->log("TCP", Log::DEBUG, "too many writes");
281         pthread_mutex_unlock(&sendLock);
282         return 0;
283       }
284     }
285   }
286 }
287
288 void TCP::dump(unsigned char* data, USHORT size)
289 {
290   printf("Size = %u\n", size);
291
292   USHORT c = 0;
293   while(c < size)
294   {
295     if ((size - c) > 15)
296     {
297       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",
298         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
299         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
300         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]),
301         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]));
302       c += 16;
303     }
304     else
305     {
306       switch (size - c)
307       {
308         case 15:
309           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",
310             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
311             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
312             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]),
313             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]));
314           c += 15;
315           break;
316         case 14:
317           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",
318             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
319             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
320             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]),
321             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
322           c += 14;
323           break;
324         case 13:
325           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",
326             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
327             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
328             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]),
329             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
330           c += 13;
331           break;
332         case 12:
333           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",
334             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
335             data[c+8], data[c+9], data[c+10], data[c+11],
336             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]),
337             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
338           c += 12;
339           break;
340         case 11:
341           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
342             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
343             data[c+8], data[c+9], data[c+10],
344             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]),
345             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
346           c += 11;
347           break;
348         case 10:
349           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
350             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
351             data[c+8], data[c+9],
352             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]),
353             dcc(data[c+8]), dcc(data[c+9]));
354           c += 10;
355           break;
356         case 9:
357           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
358             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
359             data[c+8],
360             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]),
361             dcc(data[c+8]));
362           c += 9;
363           break;
364         case 8:
365           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
366             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
367             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]));
368           c += 8;
369           break;
370         case 7:
371           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
372             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
373             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]));
374           c += 7;
375           break;
376         case 6:
377           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
378             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
379             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
380           c += 6;
381           break;
382         case 5:
383           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
384             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
385             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
386           c += 5;
387           break;
388         case 4:
389           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
390             data[c], data[c+1], data[c+2], data[c+3],
391             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
392           c += 4;
393           break;
394         case 3:
395           printf(" %02X %02X %02X                                            %c%c%c\n",
396             data[c], data[c+1], data[c+2],
397             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
398           c += 3;
399           break;
400         case 2:
401           printf(" %02X %02X                                               %c%c\n",
402             data[c], data[c+1],
403             dcc(data[c]), dcc(data[c+1]));
404           c += 2;
405           break;
406         case 1:
407           printf(" %02X                                                  %c\n",
408             data[c],
409             dcc(data[c]));
410           c += 1;
411           break;
412       }
413     }
414   }
415 }
416
417 unsigned char TCP::dcc(UCHAR c)
418 {
419   if (isspace(c)) return ' ';
420   if (isprint(c)) return c;
421   return '.';
422 }