Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5735 was 5733, checked in by rennerc, 19 years ago

network_socket: changed type of ip in constructor

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