]> git.vomp.tv Git - vompclient.git/blob - tcp.cc
Zero length recording segfault fixed
[vompclient.git] / tcp.cc
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()
25 {
26   sock = 0;
27   connected = 0;
28   timeoutEnabled = 1;
29 }
30
31 TCP::~TCP()
32 {
33   if (connected)
34   {
35     close(sock);
36     Log::getInstance()->log("TCP", Log::DEBUG, "Have closed");
37   }
38 }
39
40 void TCP::disableTimeout()
41 {
42   timeoutEnabled = 0;
43 }
44
45 void TCP::getMAC(char* dest)
46 {
47   struct ifreq ifr;
48   strcpy(ifr.ifr_name, "eth0");
49   ioctl(sock, SIOCGIFHWADDR, &ifr);
50   memcpy(dest, ifr.ifr_hwaddr.sa_data, 6);
51 }
52
53 int TCP::connectTo(char* host, unsigned short port)
54 {
55   sock = socket(PF_INET, SOCK_STREAM, 0);
56   if (sock == -1) return 0;
57
58   struct sockaddr_in dest_addr;
59   dest_addr.sin_family = AF_INET;
60   dest_addr.sin_port = htons(port);
61
62   if (!inet_aton(host, &dest_addr.sin_addr))
63   {
64     close(sock);
65     return 0;
66   }
67
68   memset(&(dest_addr.sin_zero), '\0', 8);
69
70   // set non blocking
71   int oldflags = fcntl (sock, F_GETFL, 0);
72   oldflags |= O_NONBLOCK;
73   fcntl(sock, F_SETFL, oldflags);
74
75 //  setReceiveWindow(2048);
76
77   // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!)
78
79   int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
80
81   if (success == 0)  // if by some miracle the connection succeeded in no time flat, just return!
82   {
83     connected = 1;
84     return 1;
85   }
86
87   // first check errno for EINPROGRESS, otherwise it's a fail
88   // this doesn't work?
89   if (errno != EINPROGRESS)
90   {
91     close(sock);
92     return 0;
93   }
94
95   // now do a timeout wait on writability on the socket
96
97   fd_set connectSet;
98   struct timeval timeout;
99   FD_ZERO(&connectSet);
100   FD_SET(sock, &connectSet);
101   timeout.tv_sec = 10;
102   timeout.tv_usec = 0;
103   success = select(sock + 1, NULL, &connectSet, NULL, &timeout);
104   if (success < 1)
105   {
106     // timeout or error
107     close(sock);
108     return 0;
109   }
110
111   // so the socket became available for writing. Contrary to expectation, this doesn't actually
112   // mean it connected...
113
114   int soError;
115   socklen_t soErrorSize = sizeof(soError);
116   int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, &soError, &soErrorSize);
117
118   if ((gso == 0) && (soError == 0))
119   {
120     // success!
121     connected = 1;
122     return 1;
123   }
124   else
125   {
126     close(sock);
127     return 0;
128   }
129
130 /*
131 The full documentation:
132
133        EINPROGRESS
134               The  socket is non-blocking and the connection canĀ­
135               not be completed immediately.  It  is  possible  to
136               select(2)  or  poll(2)  for completion by selecting
137               the socket  for  writing.  After  select  indicates
138               writability, use getsockopt(2) to read the SO_ERROR
139               option at level  SOL_SOCKET  to  determine  whether
140               connect  completed  successfully (SO_ERROR is zero)
141               or unsuccessfully (SO_ERROR is  one  of  the  usual
142               error  codes listed here, explaining the reason for
143               the failure).
144 */
145 }
146
147 void TCP::setReceiveWindow(size_t rxBufferSize)
148 {
149   // Set receive window
150   int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rxBufferSize, sizeof(size_t));
151   Log::getInstance()->log("TCP", Log::DEBUG, "Set receive window to %i, success(=0): %i", rxBufferSize, r);
152 }
153
154 void TCP::assignSocket(int tsocket)
155 {
156   sock = tsocket;
157 }
158
159 int TCP::isConnected()
160 {
161   return connected;
162 }
163
164 int TCP::sendPacket(void* bufR, size_t count)
165 {
166   size_t bytes_sent = 0;
167   int this_write;
168   int temp_write;
169
170   unsigned char* buf = (unsigned char*)bufR;
171
172   while (bytes_sent < count)
173   {
174     do
175     {
176       temp_write = this_write = write(sock, buf, count - bytes_sent);
177 //      Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", temp_write);
178     } while ( (this_write < 0) && (errno == EINTR) );
179
180
181     if (this_write <= 0)
182     {
183       return(this_write);
184     }
185     bytes_sent += this_write;
186     buf += this_write;
187   }
188   return(count);
189 }
190
191 UCHAR* TCP::receivePacket()
192 {
193   ULONG packetLength;
194   int success;
195
196   success = readData((UCHAR*)&packetLength, sizeof(int));
197   if (!success) return NULL;
198
199   packetLength = ntohl(packetLength);
200
201   if (packetLength > 500000)
202   {
203     Log::getInstance()->log("TCP", Log::ERR, "Received packet > 500000");
204     return NULL;
205   }
206   if (packetLength == 0)
207   {
208     Log::getInstance()->log("TCP", Log::ERR, "Received packet len = 0");
209     return NULL;
210   }
211
212   UCHAR* buffer = (UCHAR*) malloc(packetLength);
213
214   success = readData(buffer, packetLength);
215
216   if (!success)
217   {
218     Log::getInstance()->log("TCP", Log::ERR, "readData failed");
219     free(buffer);
220     close(sock);
221     connected = 0;
222     return NULL;
223   }
224
225   dataLength = packetLength;
226   return buffer;
227 }
228
229 int TCP::getDataLength()
230 {
231   return dataLength;
232 }
233
234 int TCP::readData(UCHAR* buffer, int totalBytes)
235 {
236
237   int bytesRead = 0;
238   int thisRead;
239   int readTries = 0;
240   int success;
241   fd_set readSet;
242   struct timeval timeout;
243   struct timeval* passToSelect;
244
245   if (timeoutEnabled) passToSelect = &timeout;
246   else passToSelect = NULL;
247
248   while(1)
249   {
250     FD_ZERO(&readSet);
251     FD_SET(sock, &readSet);
252     timeout.tv_sec = 10;
253     timeout.tv_usec = 0;
254     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
255     if (success < 1)
256     {
257       Log::getInstance()->log("TCP", Log::ERR, "Error or timeout");
258       return 0;  // error, or timeout
259     }
260
261     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
262 //    printf("read %i\n", thisRead);
263     if (!thisRead)
264     {
265       // if read returns 0 then connection is closed
266       // in non-blocking mode if read is called with no data available, it returns -1
267       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
268       Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed");
269       connected = 0;
270       return 0;
271     }
272     bytesRead += thisRead;
273
274     if (bytesRead == totalBytes)
275     {
276       return 1;
277     }
278     else
279     {
280       if (++readTries == 100)
281       {
282 //        Log::getInstance()->log("TCP", Log::ERR, "Too many reads");
283 //        return 0;
284       }
285     }
286   }
287 }
288
289 void TCP::dump(unsigned char* data, ULONG size)
290 {
291   printf("Size = %lu\n", size);
292
293   ULONG c = 0;
294   while(c < size)
295   {
296     if ((size - c) > 15)
297     {
298       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",
299         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
300         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
301         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]),
302         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]));
303       c += 16;
304     }
305     else
306     {
307       switch (size - c)
308       {
309         case 15:
310           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",
311             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
312             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
313             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]),
314             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]));
315           c += 15;
316           break;
317         case 14:
318           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",
319             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
320             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
321             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]),
322             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
323           c += 14;
324           break;
325         case 13:
326           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",
327             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
328             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
329             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]),
330             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
331           c += 13;
332           break;
333         case 12:
334           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",
335             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
336             data[c+8], data[c+9], data[c+10], data[c+11],
337             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]),
338             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
339           c += 12;
340           break;
341         case 11:
342           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
343             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
344             data[c+8], data[c+9], data[c+10],
345             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]),
346             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
347           c += 11;
348           break;
349         case 10:
350           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
351             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
352             data[c+8], data[c+9],
353             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]),
354             dcc(data[c+8]), dcc(data[c+9]));
355           c += 10;
356           break;
357         case 9:
358           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
359             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
360             data[c+8],
361             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]),
362             dcc(data[c+8]));
363           c += 9;
364           break;
365         case 8:
366           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
367             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
368             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]));
369           c += 8;
370           break;
371         case 7:
372           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
373             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
374             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]));
375           c += 7;
376           break;
377         case 6:
378           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
379             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
380             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
381           c += 6;
382           break;
383         case 5:
384           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
385             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
386             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
387           c += 5;
388           break;
389         case 4:
390           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
391             data[c], data[c+1], data[c+2], data[c+3],
392             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
393           c += 4;
394           break;
395         case 3:
396           printf(" %02X %02X %02X                                            %c%c%c\n",
397             data[c], data[c+1], data[c+2],
398             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
399           c += 3;
400           break;
401         case 2:
402           printf(" %02X %02X                                               %c%c\n",
403             data[c], data[c+1],
404             dcc(data[c]), dcc(data[c+1]));
405           c += 2;
406           break;
407         case 1:
408           printf(" %02X                                                  %c\n",
409             data[c],
410             dcc(data[c]));
411           c += 1;
412           break;
413       }
414     }
415   }
416 }
417
418 UCHAR TCP::dcc(UCHAR c)
419 {
420   if (isspace(c)) return ' ';
421   if (isprint(c)) return c;
422   return '.';
423 }