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