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