Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5730 was 5729, checked in by hdavid, 19 years ago

NetworkSocket

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