zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDLnetTCP.c
Go to the documentation of this file.
1 /*
2  SDL_net: An example cross-platform network library for use with SDL
3  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 /* $Id$ */
23 
24 #include "SDLnetsys.h"
25 #include "SDL_net.h"
26 
27 /* The network API for TCP sockets */
28 
29 /* Since the UNIX/Win32/BeOS code is so different from MacOS,
30  we'll just have two completely different sections here.
31 */
32 
33 struct _TCPsocket {
34  int ready;
35  SOCKET channel;
36  IPaddress remoteAddress;
37  IPaddress localAddress;
38  int sflag;
39 };
40 
41 /* Open a TCP network socket
42  If 'remote' is NULL, this creates a local server socket on the given port,
43  otherwise a TCP connection to the remote host and port is attempted.
44  The newly created socket is returned, or NULL if there was an error.
45 */
47 {
49  struct sockaddr_in sock_addr;
50 
51  /* Allocate a TCP socket structure */
52  sock = (TCPsocket)malloc(sizeof(*sock));
53  if ( sock == NULL ) {
54  SDLNet_SetError("Out of memory");
55  goto error_return;
56  }
57 
58  /* Open the socket */
59  sock->channel = socket(AF_INET, SOCK_STREAM, 0);
60  if ( sock->channel == INVALID_SOCKET ) {
61  SDLNet_SetError("Couldn't create socket");
62  goto error_return;
63  }
64 
65  /* Connect to remote, or bind locally, as appropriate */
66  if ( (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY) ) {
67 
68  // ######### Connecting to remote
69 
70  memset(&sock_addr, 0, sizeof(sock_addr));
71  sock_addr.sin_family = AF_INET;
72  sock_addr.sin_addr.s_addr = ip->host;
73  sock_addr.sin_port = ip->port;
74 
75  /* Connect to the remote host */
76  if ( connect(sock->channel, (struct sockaddr *)&sock_addr,
77  sizeof(sock_addr)) == SOCKET_ERROR ) {
78  SDLNet_SetError("Couldn't connect to remote host");
79  goto error_return;
80  }
81  sock->sflag = 0;
82  } else {
83 
84  // ########## Binding locally
85 
86  memset(&sock_addr, 0, sizeof(sock_addr));
87  sock_addr.sin_family = AF_INET;
88  sock_addr.sin_addr.s_addr = INADDR_ANY;
89  sock_addr.sin_port = ip->port;
90 
91 /*
92  * Windows gets bad mojo with SO_REUSEADDR:
93  * http://www.devolution.com/pipermail/sdl/2005-September/070491.html
94  * --ryan.
95  */
96 #ifndef WIN32
97  /* allow local address reuse */
98  { int yes = 1;
99  setsockopt(sock->channel, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
100  }
101 #endif
102 
103  /* Bind the socket for listening */
104  if ( bind(sock->channel, (struct sockaddr *)&sock_addr,
105  sizeof(sock_addr)) == SOCKET_ERROR ) {
106  SDLNet_SetError("Couldn't bind to local port");
107  goto error_return;
108  }
109  if ( listen(sock->channel, 5) == SOCKET_ERROR ) {
110  SDLNet_SetError("Couldn't listen to local port");
111  goto error_return;
112  }
113 
114  /* Set the socket to non-blocking mode for accept() */
115 #if defined(__BEOS__) && defined(SO_NONBLOCK)
116  /* On BeOS r5 there is O_NONBLOCK but it's for files only */
117  {
118  long b = 1;
119  setsockopt(sock->channel, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
120  }
121 #elif defined(O_NONBLOCK)
122  {
123  fcntl(sock->channel, F_SETFL, O_NONBLOCK);
124  }
125 #elif defined(WIN32)
126  {
127  unsigned long mode = 1;
128  ioctlsocket (sock->channel, FIONBIO, &mode);
129  }
130 #elif defined(__OS2__)
131  {
132  int dontblock = 1;
133  ioctl(sock->channel, FIONBIO, &dontblock);
134  }
135 #else
136 #warning How do we set non-blocking mode on other operating systems?
137 #endif
138  sock->sflag = 1;
139  }
140  sock->ready = 0;
141 
142 #ifdef TCP_NODELAY
143  /* Set the nodelay TCP option for real-time games */
144  { int yes = 1;
145  setsockopt(sock->channel, IPPROTO_TCP, TCP_NODELAY, (char*)&yes, sizeof(yes));
146  }
147 #else
148 #warning Building without TCP_NODELAY
149 #endif /* TCP_NODELAY */
150 
151  /* Fill in the channel host address */
152  sock->remoteAddress.host = sock_addr.sin_addr.s_addr;
153  sock->remoteAddress.port = sock_addr.sin_port;
154 
155  /* The socket is ready */
156  return(sock);
157 
158 error_return:
159  SDLNet_TCP_Close(sock);
160  return(NULL);
161 }
162 
163 /* Accept an incoming connection on the given server socket.
164  The newly created socket is returned, or NULL if there was an error.
165 */
167 {
168  TCPsocket sock;
169  struct sockaddr_in sock_addr;
170  socklen_t sock_alen;
171 
172  /* Only server sockets can accept */
173  if ( ! server->sflag ) {
174  SDLNet_SetError("Only server sockets can accept()");
175  return(NULL);
176  }
177  server->ready = 0;
178 
179  /* Allocate a TCP socket structure */
180  sock = (TCPsocket)malloc(sizeof(*sock));
181  if ( sock == NULL ) {
182  SDLNet_SetError("Out of memory");
183  goto error_return;
184  }
185 
186  /* Accept a new TCP connection on a server socket */
187  sock_alen = sizeof(sock_addr);
188  sock->channel = accept(server->channel, (struct sockaddr *)&sock_addr,
189  &sock_alen);
190  if ( sock->channel == INVALID_SOCKET ) {
191  SDLNet_SetError("accept() failed");
192  goto error_return;
193  }
194 #ifdef WIN32
195  {
196  /* passing a zero value, socket mode set to block on */
197  unsigned long mode = 0;
198  ioctlsocket (sock->channel, FIONBIO, &mode);
199  }
200 #elif defined(O_NONBLOCK)
201  {
202  int flags = fcntl(sock->channel, F_GETFL, 0);
203  fcntl(sock->channel, F_SETFL, flags & ~O_NONBLOCK);
204  }
205 #endif /* WIN32 */
206  sock->remoteAddress.host = sock_addr.sin_addr.s_addr;
207  sock->remoteAddress.port = sock_addr.sin_port;
208 
209  sock->sflag = 0;
210  sock->ready = 0;
211 
212  /* The socket is ready */
213  return(sock);
214 
215 error_return:
216  SDLNet_TCP_Close(sock);
217  return(NULL);
218 }
219 
220 /* Get the IP address of the remote system associated with the socket.
221  If the socket is a server socket, this function returns NULL.
222 */
224 {
225  if ( sock->sflag ) {
226  return(NULL);
227  }
228  return(&sock->remoteAddress);
229 }
230 
231 /* Send 'len' bytes of 'data' over the non-server socket 'sock'
232  This function returns the actual amount of data sent. If the return value
233  is less than the amount of data sent, then either the remote connection was
234  closed, or an unknown socket error occurred.
235 */
236 int SDLNet_TCP_Send(TCPsocket sock, const void *datap, int len)
237 {
238  const Uint8 *data = (const Uint8 *)datap; /* For pointer arithmetic */
239  int sent, left;
240 
241  /* Server sockets are for accepting connections only */
242  if ( sock->sflag ) {
243  SDLNet_SetError("Server sockets cannot send");
244  return(-1);
245  }
246 
247  /* Keep sending data until it's sent or an error occurs */
248  left = len;
249  sent = 0;
251  do {
252  len = send(sock->channel, (const char *) data, left, 0);
253  if ( len > 0 ) {
254  sent += len;
255  left -= len;
256  data += len;
257  }
258  } while ( (left > 0) && ((len > 0) || (SDLNet_GetLastError() == EINTR)) );
259 
260  return(sent);
261 }
262 
263 /* Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
264  and store them in the buffer pointed to by 'data'.
265  This function returns the actual amount of data received. If the return
266  value is less than or equal to zero, then either the remote connection was
267  closed, or an unknown socket error occurred.
268 */
269 int SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen)
270 {
271  int len;
272 
273  /* Server sockets are for accepting connections only */
274  if ( sock->sflag ) {
275  SDLNet_SetError("Server sockets cannot receive");
276  return(-1);
277  }
278 
280  do {
281  len = recv(sock->channel, (char *) data, maxlen, 0);
282  } while ( SDLNet_GetLastError() == EINTR );
283 
284  sock->ready = 0;
285  return(len);
286 }
287 
288 /* Close a TCP network socket */
290 {
291  if ( sock != NULL ) {
292  if ( sock->channel != INVALID_SOCKET ) {
293  closesocket(sock->channel);
294  }
295  free(sock);
296  }
297 }
DECLSPEC int SDLCALL SDLNet_TCP_Send(TCPsocket sock, const void *data, int len)
Definition: SDLnetTCP.c:236
DECLSPEC void SDLCALL SDLNet_SetError(const char *fmt,...)
Definition: SDLnet.c:65
#define SOCKET
Definition: SDLnetsys.h:78
Uint32 host
Definition: SDL_net.h:91
#define closesocket
Definition: SDLnetsys.h:76
GLint left
Definition: glew.h:7291
#define NULL
Definition: ftobjs.h:61
SDL_EventEntry * free
Definition: SDL_events.c:80
#define memset
Definition: SDL_malloc.c:633
int SDLNet_GetLastError(void)
Definition: SDLnet.c:51
GLenum GLsizei len
Definition: glew.h:7035
DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Accept(TCPsocket server)
Definition: SDLnetTCP.c:166
#define INADDR_NONE
Definition: SDL_net.h:105
DECLSPEC IPaddress *SDLCALL SDLNet_TCP_GetPeerAddress(TCPsocket sock)
Definition: SDLnetTCP.c:223
#define INVALID_SOCKET
Definition: SDLnetsys.h:79
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Open(IPaddress *ip)
Definition: SDLnetTCP.c:46
Uint16 port
Definition: SDL_net.h:92
#define malloc
Definition: SDL_malloc.c:635
GLenum GLsizei GLsizei GLsizei GLsizei GLbitfield flags
Definition: glew.h:2767
struct _TCPsocket * TCPsocket
Definition: SDL_net.h:131
TCPsocket sock
Definition: chatd.c:41
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
#define INADDR_ANY
Definition: SDL_net.h:102
GLdouble GLdouble GLdouble b
Definition: glew.h:8383
#define SOCKET_ERROR
Definition: SDLnetsys.h:80
DECLSPEC int SDLCALL SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen)
Definition: SDLnetTCP.c:269
void SDLNet_SetLastError(int err)
Definition: SDLnet.c:56
GLenum mode
Definition: glew.h:2394
DECLSPEC void SDLCALL SDLNet_TCP_Close(TCPsocket sock)
Definition: SDLnetTCP.c:289