Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6041 was 6041, checked in by rennerc, 18 years ago

network_socket: fixed a bug

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