]> git.vomp.tv Git - vompserver.git/blob - tcp.c
Initial import
[vompserver.git] / tcp.c
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(int tsocket)
25 {
26   sock = -1;
27   connected = 0;
28   readTimeoutEnabled = 1;
29
30   if (tsocket)
31   {
32     sock = tsocket;
33     connected = 1;
34   }
35 }
36
37 TCP::~TCP()
38 {
39   if (connected) cleanup();
40 }
41
42 void TCP::cleanup()
43 {
44   close(sock);
45   sock = -1;
46   connected = 0;
47   printf("TCP has closed socket\n");
48 }
49
50
51 void TCP::disableReadTimeout()
52 {
53   readTimeoutEnabled = 0;
54 }
55
56 int TCP::connectTo(char* host, unsigned short port)
57 {
58   sock = socket(PF_INET, SOCK_STREAM, 0);
59   if (sock == -1) return 0;
60
61   struct sockaddr_in dest_addr;
62   dest_addr.sin_family = AF_INET;
63   dest_addr.sin_port = htons(port);
64
65   if (!inet_aton(host, &dest_addr.sin_addr))
66   {
67     cleanup();
68     return 0;
69   }
70
71   memset(&(dest_addr.sin_zero), '\0', 8);
72
73   int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
74   if (success == -1)
75   {
76     cleanup();
77     return 0;
78   }
79
80   connected = 1;
81   return 1;
82 }
83
84 void TCP::setNonBlocking()
85 {
86   int oldflags = fcntl(sock, F_GETFL, 0);
87   oldflags |= O_NONBLOCK;
88   fcntl(sock, F_SETFL, oldflags);
89 }
90
91 int TCP::setSoKeepTime(int timeOut)
92 {
93   int option;
94   int s1, s2, s3, s4;
95
96   option = 1;
97   s1 = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option));
98   printf("SO_KEEPALIVE = %i\n", s1);
99
100   option = timeOut;
101   s2 = setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &option, sizeof(option));
102   printf("TCP_KEEPIDLE = %i\n", s2);
103
104   s3 = setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &option, sizeof(option));
105   printf("TCP_KEEPINTVL = %i\n", s3);
106
107   option = 2;
108   s4 = setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &option, sizeof(option));
109   printf("TCP_KEEPCNT = %i\n", s4);
110
111   if (s1 || s2 || s3 || s4) return 0;
112   return 1;
113 }
114
115 void TCP::assignSocket(int tsocket)
116 {
117   sock = tsocket;
118   connected = 1;
119 }
120
121 int TCP::isConnected()
122 {
123   return connected;
124 }
125
126 UCHAR* TCP::receivePacket()
127 {
128   if (!connected) return NULL;
129
130   int packetLength;
131   int success;
132
133   success = readData((UCHAR*)&packetLength, sizeof(int));
134   if (!success)
135   {
136     cleanup();
137     return NULL;
138   }
139
140   packetLength = ntohl(packetLength);
141
142   if (packetLength > 200000) return NULL;
143   UCHAR* buffer = (UCHAR*) malloc(packetLength);
144
145   success = readData(buffer, packetLength);
146   if (!success)
147   {
148     cleanup();
149     free(buffer);
150     return NULL;
151   }
152
153   dump((unsigned char*)buffer, packetLength);
154
155   dataLength = packetLength;
156   return buffer;
157 }
158
159 int TCP::getDataLength()
160 {
161   return dataLength;
162 }
163
164 int TCP::readData(UCHAR* buffer, int totalBytes)
165 {
166   if (!connected) return 0;
167
168   int bytesRead = 0;
169   int thisRead;
170   int readTries = 0;
171   int success;
172   fd_set readSet;
173   struct timeval timeout;
174   struct timeval* passToSelect;
175
176   if (readTimeoutEnabled) passToSelect = &timeout;
177   else passToSelect = NULL;
178
179   while(1)
180   {
181     FD_ZERO(&readSet);
182     FD_SET(sock, &readSet);
183     timeout.tv_sec = 10;
184     timeout.tv_usec = 0;
185     success = select(sock + 1, &readSet, NULL, NULL, passToSelect);
186     if (success < 1)
187     {
188       cleanup();
189       printf("TCP: error or timeout\n");
190       return 0;  // error, or timeout
191     }
192
193     thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead);
194     if (!thisRead)
195     {
196       // if read returns 0 then connection is closed
197       // in non-blocking mode if read is called with no data available, it returns -1
198       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
199       cleanup();
200       return 0;
201     }
202     bytesRead += thisRead;
203
204     printf("Bytes read now: %u\n", bytesRead);
205     if (bytesRead == totalBytes)
206     {
207       return 1;
208     }
209     else
210     {
211       if (++readTries == 100)
212       {
213         cleanup();
214         printf("too many reads\n");
215         return 0;
216       }
217     }
218   }
219 }
220
221 int TCP::sendPacket(UCHAR* buf, size_t count)
222 {
223   if (!connected) return 0;
224
225   unsigned int bytesWritten = 0;
226   int thisWrite;
227   int writeTries = 0;
228   int success;
229   fd_set writeSet;
230   struct timeval timeout;
231
232   while(1)
233   {
234     FD_ZERO(&writeSet);
235     FD_SET(sock, &writeSet);
236     timeout.tv_sec = 10;
237     timeout.tv_usec = 0;
238     success = select(sock + 1, NULL, &writeSet, NULL, &timeout);
239     if (success < 1)
240     {
241       cleanup();
242       printf("TCP: error or timeout\n");
243       return 0;  // error, or timeout
244     }
245
246     thisWrite = write(sock, &buf[bytesWritten], count - bytesWritten);
247     if (!thisWrite)
248     {
249       // if write returns 0 then connection is closed ?
250       // in non-blocking mode if read is called with no data available, it returns -1
251       // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway.
252       cleanup();
253       printf("Detected connection closed\n");
254       return 0;
255     }
256     bytesWritten += thisWrite;
257
258     printf("Bytes written now: %u\n", bytesWritten);
259     if (bytesWritten == count)
260     {
261       return 1;
262     }
263     else
264     {
265       if (++writeTries == 100)
266       {
267         cleanup();
268         printf("too many writes\n");
269         return 0;
270       }
271     }
272   }
273 }
274
275
276
277
278 void TCP::dump(unsigned char* data, USHORT size)
279 {
280   printf("Size = %u\n", size);
281
282   USHORT c = 0;
283   while(c < size)
284   {
285     if ((size - c) > 15)
286     {
287       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",
288         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
289         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
290         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]),
291         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]));
292       c += 16;
293     }
294     else
295     {
296       switch (size - c)
297       {
298         case 15:
299           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",
300             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
301             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
302             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]),
303             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]));
304           c += 15;
305           break;
306         case 14:
307           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",
308             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
309             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
310             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]),
311             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
312           c += 14;
313           break;
314         case 13:
315           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",
316             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
317             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
318             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]),
319             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
320           c += 13;
321           break;
322         case 12:
323           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",
324             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
325             data[c+8], data[c+9], data[c+10], data[c+11],
326             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]),
327             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
328           c += 12;
329           break;
330         case 11:
331           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
332             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
333             data[c+8], data[c+9], data[c+10],
334             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]),
335             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
336           c += 11;
337           break;
338         case 10:
339           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
340             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
341             data[c+8], data[c+9],
342             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]),
343             dcc(data[c+8]), dcc(data[c+9]));
344           c += 10;
345           break;
346         case 9:
347           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
348             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
349             data[c+8],
350             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]),
351             dcc(data[c+8]));
352           c += 9;
353           break;
354         case 8:
355           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
356             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
357             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]));
358           c += 8;
359           break;
360         case 7:
361           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %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],
363             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]));
364           c += 7;
365           break;
366         case 6:
367           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
368             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
369             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
370           c += 6;
371           break;
372         case 5:
373           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
374             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
375             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
376           c += 5;
377           break;
378         case 4:
379           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
380             data[c], data[c+1], data[c+2], data[c+3],
381             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
382           c += 4;
383           break;
384         case 3:
385           printf(" %02X %02X %02X                                            %c%c%c\n",
386             data[c], data[c+1], data[c+2],
387             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
388           c += 3;
389           break;
390         case 2:
391           printf(" %02X %02X                                               %c%c\n",
392             data[c], data[c+1],
393             dcc(data[c]), dcc(data[c+1]));
394           c += 2;
395           break;
396         case 1:
397           printf(" %02X                                                  %c\n",
398             data[c],
399             dcc(data[c]));
400           c += 1;
401           break;
402       }
403     }
404   }
405 }
406
407 unsigned char TCP::dcc(UCHAR c)
408 {
409   if (isspace(c)) return ' ';
410   if (isprint(c)) return c;
411   return '.';
412 }