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