Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/network/src/lib/network/network_socket.cc @ 5808

Last change on this file since 5808 was 5808, checked in by patrick, 18 years ago

network: valgrinded the network modules - zero error limit reached: small modification in NetworkSocket and ConnectionMonitor, nothing serious

File size: 10.8 KB
RevLine 
[5542]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:
[5592]12   main-programmer: Christoph Renner, David Hasenfratz
13   co-programmer:
[5542]14*/
15
16
[5605]17
[5542]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
[5565]27/* header for debug output */
28#include "debug.h"
[5542]29
[5565]30
[5542]31/**
32 * Default constructor
33 */
34NetworkSocket::NetworkSocket()
[5565]35{
[5808]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{
[5592]51  /* set the class id for the base object */
52  this->setClassID(CL_NETWORK_SOCKET, "NetworkSocket");
[5542]53
[5624]54  tcpSocket = NULL;
[5630]55  incomingBufferLength = 0;
56  outgoingBufferLength = 0;
[5624]57
[5630]58  incomingBufferMutex = SDL_CreateMutex();
59  outgoingBufferMutex = SDL_CreateMutex();
60  socketMutex = SDL_CreateMutex();
[5624]61  terminateThread = false;
62
[5592]63  /* Init SDL_net */
[5624]64  //NOTE: do we need to call SDLNet_Init for all instances?
[5592]65  if(SDLNet_Init()==-1)
66  {
67    PRINTF(1)("SDLNet_Init: %s\n", SDLNet_GetError());
[5565]68    return;
[5592]69  }
70  else
71    PRINTF(5)("SDL_net initialized\n");
[5565]72
[5606]73  PRINTF(0)("NetworkSocket created\n");
74
[5565]75}
76
[5542]77/**
78 * Default destructor
79 */
80NetworkSocket::~ NetworkSocket( )
81{
[5592]82  /* Quit SDL_net */
[5624]83  // NOTE: what if other instances of NetworkSocket running?
[5592]84  SDLNet_Quit();
85  PRINTF(5)("SDL_net shutdown\n");
[5625]86
[5630]87  _isListening = false;
88
89  SDL_DestroyMutex(incomingBufferMutex);
90  SDL_DestroyMutex(outgoingBufferMutex);
91  SDL_DestroyMutex(socketMutex);
[5542]92}
93
94/**
[5624]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 */
[5804]99void NetworkSocket::connectToServer(IPaddress ip)
[5542]100{
[5624]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  }
[5577]106
[5592]107  /* Connect to the host and port contained in ip using a TCP connection. */
108  tcpSocket = SDLNet_TCP_Open(&ip);
109  if(!tcpSocket)
110  {
[5577]111    PRINTF(1)("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
112    return;
[5592]113  }
[5577]114
[5630]115  _isListening = false;
116
[5624]117  SDL_CreateThread(thread_read, (void*)this);
[5630]118  SDL_CreateThread(thread_write, (void*)this);
[5542]119}
120
121/**
[5624]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)
[5542]127{
[5630]128  _isListening = true;
[5624]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");
[5630]133    _isListening = false;
[5624]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());
[5630]142    _isListening = false;
[5624]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());
[5630]151    _isListening = false;
[5624]152    return;
153  }
154
155  SDL_CreateThread(thread_listen, (void*)this);
[5630]156  SDL_CreateThread(thread_write, (void*)this);
[5542]157}
158
159/**
[5565]160 * DTears down a TCP/UDP connection.
[5542]161 */
162void NetworkSocket::disconnectServer( )
163{
[5624]164  terminateThread = true;
[5592]165  /* Close the connection */
[5625]166
[5630]167  SDL_mutexP(socketMutex);
[5592]168  SDLNet_TCP_Close(tcpSocket);
[5624]169  tcpSocket = NULL;
[5630]170  SDL_mutexV(socketMutex);
[5542]171}
172
[5624]173
[5542]174/**
[5624]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)
[5542]183{
[5752]184  PRINTF(0)("NetworkSocket::writeBytes()\n");
[5630]185#ifdef _USE_OUTGOING_BUFFER
[5625]186
[5630]187  //printf("length=%d, bufsize=%d\n", length, _OUTGOING_BUFFER_SIZE);
[5631]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//   }
[5630]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;
[5804]224
[5630]225  SDL_mutexV(outgoingBufferMutex);
226
[5805]227
[5630]228  return nbytes;
229#else
230  SDL_mutexP(socketMutex);
231
[5624]232  if (!tcpSocket || data==NULL)
233    return 0;
234
235  int res = SDLNet_TCP_Send(tcpSocket, data, length);
236
[5630]237  SDL_mutexV(socketMutex);
[5625]238
[5624]239  if (res<length)
240    PRINTF(1)("SDLNet_TCP_Send: %s\n", SDLNet_GetError());
[5628]241
242  return res;
[5630]243#endif
[5542]244}
245
[5624]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 */
[5614]256int NetworkSocket::readBytes(byte * data, int length)
[5542]257{
[5625]258  if (data==NULL)
[5624]259    return 0;
260
[5630]261  int nbytes = (length<incomingBufferLength) ? length : incomingBufferLength;
[5624]262
[5808]263
[5630]264  //printf("readBytes: nbytes = %d; length=%d; incomingBufferLength=%d\n", nbytes, length, incomingBufferLength);
265
[5624]266  // just in case ...
267  if (nbytes<0)
268    return -1;
269
270  if (nbytes==0)
271      return 0;
272
[5630]273  SDL_mutexP(incomingBufferMutex);
[5624]274
[5630]275  memcpy(data, incomingBuffer, nbytes);
[5624]276
277  //important: use memmove because the memory areas may overlap
[5630]278  memmove(incomingBuffer, incomingBuffer+nbytes, incomingBufferLength-nbytes);
279  incomingBufferLength -= nbytes;
[5624]280
[5630]281  SDL_mutexV(incomingBufferMutex);
[5624]282
283  return nbytes;
[5542]284}
[5624]285
286/**
[5725]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 */
[5729]293int NetworkSocket::readBlock(byte * data, int length)
[5725]294{
[5804]295  printf("NetworkSocket: got %i bytes, NetworkStream requested %i bytes\n", this->incomingBufferLength, length);
[5725]296  if (incomingBufferLength >= length)
297    return readBytes(data, length);
298  else return 0;
299}
300
301/**
[5624]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;
[5630]309  self->_isListening = true;
[5624]310  TCPsocket tempsocket;
311
312  tempsocket = SDLNet_TCP_Accept(self->tcpSocket);
313
[5630]314  while (!tempsocket && !self->terminateThread)
315    tempsocket = SDLNet_TCP_Accept(self->tcpSocket);
316
317  SDL_mutexP(self->socketMutex);
[5624]318  SDLNet_TCP_Close(self->tcpSocket);
319  self->tcpSocket = NULL;
320
321  if (!tempsocket)
322  {
[5737]323    printf("SDLNet_TCP_Accept: %s\n", SDLNet_GetError());
[5630]324    //printf("SDLNet_TCP_Accept: %s\n", SDLNet_GetError());
325    SDL_mutexV(self->socketMutex);
326    self->_isListening = false;
[5624]327    return -1;
328  }
329
330  self->tcpSocket = tempsocket;
331
[5630]332  SDL_mutexV(self->socketMutex);
[5625]333
[5630]334  self->_isListening = false;
[5624]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
[5630]352    nbytestoread = min(_INCOMING_BUFFER_SIZE - self->incomingBufferLength, _LOCAL_BUFFER_SIZE);
353#undef min
[5624]354
[5628]355    //if buffer is full
[5630]356    if (nbytestoread<=0 || self->_isListening)
[5628]357    {
358      SDL_Delay(_MSECONDS_SLEEP_FULL_BUFFER);
359      continue;
360    }
361
[5624]362    nbytesread = SDLNet_TCP_Recv(self->tcpSocket, buffer, nbytestoread);
363
[5630]364    SDL_mutexP(self->incomingBufferMutex);
[5624]365
366    if (nbytesread<=0)
367    {
[5737]368      printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
[5625]369
[5630]370      SDL_mutexP(self->socketMutex);
[5625]371
[5624]372      SDLNet_TCP_Close(self->tcpSocket);
373      self->tcpSocket = NULL;
[5625]374
[5630]375      SDL_mutexV(self->socketMutex);
376      SDL_mutexV(self->incomingBufferMutex);
[5624]377      return -1;
378    }
379
[5630]380    //printf("thread_read: nbytesread=%d\n", nbytesread);
[5624]381
[5630]382    memcpy(self->incomingBuffer+self->incomingBufferLength, buffer, nbytesread);
383    self->incomingBufferLength += nbytesread;
384
385    SDL_mutexV(self->incomingBufferMutex);
[5624]386  }
387
388  return 0;
389}
390
[5630]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;
[5624]397
[5630]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
[5628]403
[5805]404//     printf("thread_write nbytes=%d listening=%d\n", nbytestowrite, (int)self->_isListening);
[5630]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    {
[5737]427      printf("SDLNet_TCP_Recv: %s\n", SDLNet_GetError());
[5630]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
[5805]440  printf("QUIT WRITE THREAD\n");
[5630]441  return 0;
442}
443
Note: See TracBrowser for help on using the repository browser.