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