Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/network/network_socket.cc @ 5898

Last change on this file since 5898 was 5822, checked in by bensch, 19 years ago

orxonox/trunk: merged branches/network to the trunk
merged with command:
svn merge -r 5505:HEAD branches/network trunk

conflicts resolved in favor of the trunk (as always :))
also fixed a typo in the #include "SDL_tread.h"

File size: 10.8 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Christoph Renner, David Hasenfratz
13   co-programmer:
14*/
15
16
17
18/* this is for debug output. It just says, that all calls to PRINT() belong to the DEBUG_MODULE_NETWORK module
19   For more information refere to https://www.orxonox.net/cgi-bin/trac.cgi/wiki/DebugOutput
20*/
21#define DEBUG_MODULE_NETWORK
22
23
24/* include your own header */
25#include "network_socket.h"
26
27/* header for debug output */
28#include "debug.h"
29
30
31/**
32 * Default constructor
33 */
34NetworkSocket::NetworkSocket()
35{
36  this->init();
37}
38
39/**
40 * Constructor to connect directly
41 */
42NetworkSocket::NetworkSocket(IPaddress ip)
43{
44  this->init();
45  connectToServer(ip);
46}
47
48
49void NetworkSocket::init()
50{
51  /* set the class id for the base object */
52  this->setClassID(CL_NETWORK_SOCKET, "NetworkSocket");
53
54  tcpSocket = NULL;
55  incomingBufferLength = 0;
56  outgoingBufferLength = 0;
57
58  incomingBufferMutex = SDL_CreateMutex();
59  outgoingBufferMutex = SDL_CreateMutex();
60  socketMutex = SDL_CreateMutex();
61  terminateThread = false;
62
63  /* Init SDL_net */
64  //NOTE: do we need to call SDLNet_Init for all instances?
65  if(SDLNet_Init()==-1)
66  {
67    PRINTF(1)("SDLNet_Init: %s\n", SDLNet_GetError());
68    return;
69  }
70  else
71    PRINTF(5)("SDL_net initialized\n");
72
73  PRINTF(0)("NetworkSocket created\n");
74
75}
76
77/**
78 * Default destructor
79 */
80NetworkSocket::~ NetworkSocket( )
81{
82  /* Quit SDL_net */
83  // NOTE: what if other instances of NetworkSocket running?
84  SDLNet_Quit();
85  PRINTF(5)("SDL_net shutdown\n");
86
87  _isListening = false;
88
89  SDL_DestroyMutex(incomingBufferMutex);
90  SDL_DestroyMutex(outgoingBufferMutex);
91  SDL_DestroyMutex(socketMutex);
92}
93
94/**
95 * This function establishes a TCP/UDP connection to a given server (function argument).
96 * It is called by the NetworkStream. It creates a TCP/UDP socket for the connection.
97 * @param ip
98 */
99void NetworkSocket::connectToServer(IPaddress ip)
100{
101  //check if not already connected or listening
102  if (tcpSocket)
103  {
104    PRINTF(1)("NetworkSocket::listen: tcpSocket!=NULL! maybe you already called listen or connectToServer or did not call disconnectServer()!");
105  }
106
107  /* Connect to the host and port contained in ip using a TCP connection. */
108  tcpSocket = SDLNet_TCP_Open(&ip);
109  if(!tcpSocket)
110  {
111    PRINTF(1)("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
112    return;
113  }
114
115  _isListening = false;
116
117  SDL_CreateThread(thread_read, (void*)this);
118  SDL_CreateThread(thread_write, (void*)this);
119}
120
121/**
122 * Tells the NetworkSocket to listen on a specific port for incoming connections.
123 * NetworkSocket::writeBytes(...) will have no effect until there is a valuable connection.
124 * @param port
125 */
126void NetworkSocket::listen(unsigned int port)
127{
128  _isListening = true;
129  //check if not already connected or listening
130  if (tcpSocket)
131  {
132    PRINTF(1)("NetworkSocket::listen: tcpSocket!=NULL! maybe you already called listen or connectToServer or did not call disconnectServer()!\n");
133    _isListening = false;
134    return;
135  }
136
137  IPaddress ip;
138
139  if (SDLNet_ResolveHost(&ip, NULL, port)==-1)
140  {
141    PRINTF(1)("SDLNet_ResolveHost: %s\n", SDLNet_GetError());
142    _isListening = false;
143    return;
144  }
145
146  tcpSocket = SDLNet_TCP_Open(&ip);
147
148  if (!tcpSocket)
149  {
150    PRINTF(1)("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
151    _isListening = false;
152    return;
153  }
154
155  SDL_CreateThread(thread_listen, (void*)this);
156  SDL_CreateThread(thread_write, (void*)this);
157}
158
159/**
160 * DTears down a TCP/UDP connection.
161 */
162void NetworkSocket::disconnectServer( )
163{
164  terminateThread = true;
165  /* Close the connection */
166
167  SDL_mutexP(socketMutex);
168  SDLNet_TCP_Close(tcpSocket);
169  tcpSocket = NULL;
170  SDL_mutexV(socketMutex);
171}
172
173
174/**
175 * This function writes some bytes (data) to the network connection (if the connection is already
176 * estabilhed) otherwise it just does nothing (silently discarding the data). And writes some
177 * warnings
178 * @param data: pointer to the data to send
179 * @param length: n bytes to send
180 * @return the number successfully written bytes
181 */
182int NetworkSocket::writeBytes(byte * data, int length)
183{
184  PRINTF(0)("NetworkSocket::writeBytes()\n");
185#ifdef _USE_OUTGOING_BUFFER
186
187  //printf("length=%d, bufsize=%d\n", length, _OUTGOING_BUFFER_SIZE);
188//   if (length>_OUTGOING_BUFFER_SIZE)
189//   {
190//     int res = 0;
191//     int n = length / _OUTGOING_BUFFER_SIZE;
192//     if (length % _OUTGOING_BUFFER_SIZE != 0)
193//       n++;
194// //     printf("n=%d\n", n);
195//     SDL_Delay(500);
196//     for (int i = 0; i<n; i++)
197//     {
198// //       printf("i=%d\n", i);
199//       if (i==n-1)
200//       {
201//         res += writeBytes(data + i*_OUTGOING_BUFFER_SIZE, length-i*_OUTGOING_BUFFER_SIZE);
202// //         printf("res = %d\n", res);
203//       }
204//       else
205//       {
206//         res += writeBytes(data + i*_OUTGOING_BUFFER_SIZE, _OUTGOING_BUFFER_SIZE);
207// //         printf("res = %d\n", res);
208//       }
209//     }
210//     return res;
211//   }
212
213#define min(a,b) (a<b)?a:b
214  int nbytes = min(_OUTGOING_BUFFER_SIZE - outgoingBufferLength, length);
215#undef min
216
217  if (!tcpSocket || data==NULL || nbytes<=0)
218    return 0;
219
220  SDL_mutexP(outgoingBufferMutex);
221
222  memcpy(outgoingBuffer + outgoingBufferLength, data, nbytes);
223  outgoingBufferLength += nbytes;
224
225  SDL_mutexV(outgoingBufferMutex);
226
227
228  return nbytes;
229#else
230  SDL_mutexP(socketMutex);
231
232  if (!tcpSocket || data==NULL)
233    return 0;
234
235  int res = SDLNet_TCP_Send(tcpSocket, data, length);
236
237  SDL_mutexV(socketMutex);
238
239  if (res<length)
240    PRINTF(1)("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
241
242  return res;
243#endif
244}
245
246/**
247 * Reads in the bytes from the network interface and passes it to the NetworkStream.
248 * This function must internaly be implemented/connected as a thread, since the read
249 * functions of many network libraries are blocking an would therefore block the whole
250 * program.
251 * From outside, the thread shouldn't be accessible at all.
252 * @param data: pointer to memory, big enough to store length bytes
253 * @param length: n bytes to read
254 * @return the number successfully read bytes. -1 on error. may be less than length!
255 */
256int NetworkSocket::readBytes(byte * data, int length)
257{
258  if (data==NULL)
259    return 0;
260
261  int nbytes = (length<incomingBufferLength) ? length : incomingBufferLength;
262
263
264  //printf("readBytes: nbytes = %d; length=%d; incomingBufferLength=%d\n", nbytes, length, incomingBufferLength);
265
266  // just in case ...
267  if (nbytes<0)
268    return -1;
269
270  if (nbytes==0)
271      return 0;
272
273  SDL_mutexP(incomingBufferMutex);
274
275  memcpy(data, incomingBuffer, nbytes);
276
277  //important: use memmove because the memory areas may overlap
278  memmove(incomingBuffer, incomingBuffer+nbytes, incomingBufferLength-nbytes);
279  incomingBufferLength -= nbytes;
280
281  SDL_mutexV(incomingBufferMutex);
282
283  return nbytes;
284}
285
286/**
287 * Reads in the bytes form the network interface and passes it to the NetworkStream.
288 * It only reads the bytes if there are enough bytes in our buffer.
289 * @param data: pointer to memory, big enough to store length bytes
290 * @param length: n bytes to read
291 * @return the number successfully read bytes. -1 on error. 0 if there are not enough bytes in our buffer.
292 */
293int NetworkSocket::readBlock(byte * data, int length)
294{
295  printf("NetworkSocket: got %i bytes, NetworkStream requested %i bytes\n", this->incomingBufferLength, length);
296  if (incomingBufferLength >= length)
297    return readBytes(data, length);
298  else return 0;
299}
300
301/**
302 * used to create a thread to listen
303 * will call thrad_read when established connection
304 * @param data: pointer to NetwortSocket
305 */
306int NetworkSocket::thread_listen( void * data )
307{
308  NetworkSocket * self = (NetworkSocket*)data;
309  self->_isListening = true;
310  TCPsocket tempsocket;
311
312  tempsocket = SDLNet_TCP_Accept(self->tcpSocket);
313
314  while (!tempsocket && !self->terminateThread)
315    tempsocket = SDLNet_TCP_Accept(self->tcpSocket);
316
317  SDL_mutexP(self->socketMutex);
318  SDLNet_TCP_Close(self->tcpSocket);
319  self->tcpSocket = NULL;
320
321  if (!tempsocket)
322  {
323    printf("SDLNet_TCP_Accept: %s\n", SDLNet_GetError());
324    //printf("SDLNet_TCP_Accept: %s\n", SDLNet_GetError());
325    SDL_mutexV(self->socketMutex);
326    self->_isListening = false;
327    return -1;
328  }
329
330  self->tcpSocket = tempsocket;
331
332  SDL_mutexV(self->socketMutex);
333
334  self->_isListening = false;
335  return thread_read(data);
336}
337
338/**
339 * used to create a thread to read from socket
340 * @param data: pointer to NetworkSocket
341 */
342int NetworkSocket::thread_read( void * data )
343{
344  int nbytesread = 0;
345  int nbytestoread = 0;
346  char buffer[_LOCAL_BUFFER_SIZE];
347  NetworkSocket * self = (NetworkSocket*)data;
348
349  while (!self->terminateThread)
350  {
351#define min(a,b) (a<b)?a:b
352    nbytestoread = min(_INCOMING_BUFFER_SIZE - self->incomingBufferLength, _LOCAL_BUFFER_SIZE);
353#undef min
354
355    //if buffer is full
356    if (nbytestoread<=0 || self->_isListening)
357    {
358      SDL_Delay(_MSECONDS_SLEEP_FULL_BUFFER);
359      continue;
360    }
361
362    nbytesread = SDLNet_TCP_Recv(self->tcpSocket, buffer, nbytestoread);
363
364    SDL_mutexP(self->incomingBufferMutex);
365
366    if (nbytesread<=0)
367    {
368      printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
369
370      SDL_mutexP(self->socketMutex);
371
372      SDLNet_TCP_Close(self->tcpSocket);
373      self->tcpSocket = NULL;
374
375      SDL_mutexV(self->socketMutex);
376      SDL_mutexV(self->incomingBufferMutex);
377      return -1;
378    }
379
380    //printf("thread_read: nbytesread=%d\n", nbytesread);
381
382    memcpy(self->incomingBuffer+self->incomingBufferLength, buffer, nbytesread);
383    self->incomingBufferLength += nbytesread;
384
385    SDL_mutexV(self->incomingBufferMutex);
386  }
387
388  return 0;
389}
390
391int NetworkSocket::thread_write( void * data )
392{
393  int nbyteswrite = 0;
394  int nbytestowrite = 0;
395  char buffer[_LOCAL_BUFFER_SIZE];
396  NetworkSocket * self = (NetworkSocket*)data;
397
398  while (!self->terminateThread)
399  {
400#define min(a,b) (a<b)?a:b
401    nbytestowrite = min(self->outgoingBufferLength, _LOCAL_BUFFER_SIZE);
402#undef min
403
404//     printf("thread_write nbytes=%d listening=%d\n", nbytestowrite, (int)self->_isListening);
405
406    //if buffer is full
407    if (nbytestowrite<=0 || self->_isListening)
408    {
409      SDL_Delay(_MSECONDS_SLEEP_EMPTY_BUFFER);
410      continue;
411    }
412
413    SDL_mutexP(self->outgoingBufferMutex);
414
415    //printf("a\n");
416
417    memcpy(buffer, self->outgoingBuffer, nbytestowrite);
418    self->outgoingBufferLength -= nbytestowrite;
419    memmove(self->outgoingBuffer, self->outgoingBuffer+nbytestowrite, self->outgoingBufferLength);
420
421    SDL_mutexV(self->outgoingBufferMutex);
422
423    nbyteswrite = SDLNet_TCP_Send(self->tcpSocket, buffer, nbytestowrite);
424
425    if (nbyteswrite<=0)
426    {
427      printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
428
429      SDL_mutexP(self->socketMutex);
430
431      SDLNet_TCP_Close(self->tcpSocket);
432      self->tcpSocket = NULL;
433
434      SDL_mutexV(self->socketMutex);
435      return -1;
436    }
437
438  }
439
440  printf("QUIT WRITE THREAD\n");
441  return 0;
442}
443
Note: See TracBrowser for help on using the repository browser.