zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
chatd.c
Go to the documentation of this file.
1 /*
2  CHATD: A chat server using the SDL example network library
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 /* Note that this isn't necessarily the way to run a chat system.
23  This is designed to excercise the network code more than be really
24  functional.
25 */
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include "SDL.h"
32 #include "SDL_net.h"
33 #include "chat.h"
34 
35 /* This is really easy. All we do is monitor connections */
36 
39 static struct {
40  int active;
43  Uint8 name[256+1];
45 
46 
47 void HandleServer(void)
48 {
49  TCPsocket newsock;
50  int which;
51  unsigned char data;
52 
53  newsock = SDLNet_TCP_Accept(servsock);
54  if ( newsock == NULL ) {
55  return;
56  }
57 
58  /* Look for unconnected person slot */
59  for ( which=0; which<CHAT_MAXPEOPLE; ++which ) {
60  if ( ! people[which].sock ) {
61  break;
62  }
63  }
64  if ( which == CHAT_MAXPEOPLE ) {
65  /* Look for inactive person slot */
66  for ( which=0; which<CHAT_MAXPEOPLE; ++which ) {
67  if ( people[which].sock && ! people[which].active ) {
68  /* Kick them out.. */
69  data = CHAT_BYE;
70  SDLNet_TCP_Send(people[which].sock, &data, 1);
72  people[which].sock);
73  SDLNet_TCP_Close(people[which].sock);
74 #ifdef DEBUG
75  fprintf(stderr, "Killed inactive socket %d\n", which);
76 #endif
77  break;
78  }
79  }
80  }
81  if ( which == CHAT_MAXPEOPLE ) {
82  /* No more room... */
83  data = CHAT_BYE;
84  SDLNet_TCP_Send(newsock, &data, 1);
85  SDLNet_TCP_Close(newsock);
86 #ifdef DEBUG
87  fprintf(stderr, "Connection refused -- chat room full\n");
88 #endif
89  } else {
90  /* Add socket as an inactive person */
91  people[which].sock = newsock;
92  people[which].peer = *SDLNet_TCP_GetPeerAddress(newsock);
94 #ifdef DEBUG
95  fprintf(stderr, "New inactive socket %d\n", which);
96 #endif
97  }
98 }
99 
100 /* Send a "new client" notification */
101 void SendNew(int about, int to)
102 {
103  char data[512];
104  int n;
105 
106  n = strlen((char *)people[about].name)+1;
107  data[0] = CHAT_ADD;
108  data[CHAT_ADD_SLOT] = about;
109  memcpy(&data[CHAT_ADD_HOST], &people[about].peer.host, 4);
110  memcpy(&data[CHAT_ADD_PORT], &people[about].peer.port, 2);
111  data[CHAT_ADD_NLEN] = n;
112  memcpy(&data[CHAT_ADD_NAME], people[about].name, n);
113  SDLNet_TCP_Send(people[to].sock, data, CHAT_ADD_NAME+n);
114 }
115 
116 void HandleClient(int which)
117 {
118  char data[512];
119  int i;
120 
121  /* Has the connection been closed? */
122  if ( SDLNet_TCP_Recv(people[which].sock, data, 512) <= 0 ) {
123 #ifdef DEBUG
124  fprintf(stderr, "Closing socket %d (was%s active)\n",
125  which, people[which].active ? "" : " not");
126 #endif
127  /* Notify all active clients */
128  if ( people[which].active ) {
129  people[which].active = 0;
130  data[0] = CHAT_DEL;
131  data[CHAT_DEL_SLOT] = which;
132  for ( i=0; i<CHAT_MAXPEOPLE; ++i ) {
133  if ( people[i].active ) {
134  SDLNet_TCP_Send(people[i].sock,data,CHAT_DEL_LEN);
135  }
136  }
137  }
138  SDLNet_TCP_DelSocket(socketset, people[which].sock);
139  SDLNet_TCP_Close(people[which].sock);
140  people[which].sock = NULL;
141  } else {
142  switch (data[0]) {
143  case CHAT_HELLO: {
144  /* Yay! An active connection */
145  memcpy(&people[which].peer.port,
146  &data[CHAT_HELLO_PORT], 2);
147  memcpy(people[which].name,
148  &data[CHAT_HELLO_NAME], 256);
149  people[which].name[256] = 0;
150 #ifdef DEBUG
151  fprintf(stderr, "Activating socket %d (%s)\n",
152  which, people[which].name);
153 #endif
154  /* Notify all active clients */
155  for ( i=0; i<CHAT_MAXPEOPLE; ++i ) {
156  if ( people[i].active ) {
157  SendNew(which, i);
158  }
159  }
160 
161  /* Notify about all active clients */
162  people[which].active = 1;
163  for ( i=0; i<CHAT_MAXPEOPLE; ++i ) {
164  if ( people[i].active ) {
165  SendNew(i, which);
166  }
167  }
168  }
169  break;
170  default: {
171  /* Unknown packet type?? */;
172  }
173  break;
174  }
175  }
176 }
177 
178 static void cleanup(int exitcode)
179 {
180  if ( servsock != NULL ) {
182  servsock = NULL;
183  }
184  if ( socketset != NULL ) {
186  socketset = NULL;
187  }
188  SDLNet_Quit();
189  SDL_Quit();
190  exit(exitcode);
191 }
192 
193 main(int argc, char *argv[])
194 {
195  IPaddress serverIP;
196  int i;
197 
198  /* Initialize SDL */
199  if ( SDL_Init(0) < 0 ) {
200  fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
201  exit(1);
202  }
203 
204  /* Initialize the network */
205  if ( SDLNet_Init() < 0 ) {
206  fprintf(stderr, "Couldn't initialize net: %s\n",
207  SDLNet_GetError());
208  SDL_Quit();
209  exit(1);
210  }
211 
212  /* Initialize the channels */
213  for ( i=0; i<CHAT_MAXPEOPLE; ++i ) {
214  people[i].active = 0;
215  people[i].sock = NULL;
216  }
217 
218  /* Allocate the socket set */
219  socketset = SDLNet_AllocSocketSet(CHAT_MAXPEOPLE+1);
220  if ( socketset == NULL ) {
221  fprintf(stderr, "Couldn't create socket set: %s\n",
222  SDLNet_GetError());
223  cleanup(2);
224  }
225 
226  /* Create the server socket */
227  SDLNet_ResolveHost(&serverIP, NULL, CHAT_PORT);
228 printf("Server IP: %x, %d\n", serverIP.host, serverIP.port);
229  servsock = SDLNet_TCP_Open(&serverIP);
230  if ( servsock == NULL ) {
231  fprintf(stderr, "Couldn't create server socket: %s\n",
232  SDLNet_GetError());
233  cleanup(2);
234  }
236 
237  /* Loop, waiting for network events */
238  for ( ; ; ) {
239  /* Wait for events */
241 
242  /* Check for new connections */
243  if ( SDLNet_SocketReady(servsock) ) {
244  HandleServer();
245  }
246 
247  /* Check for events on existing clients */
248  for ( i=0; i<CHAT_MAXPEOPLE; ++i ) {
249  if ( SDLNet_SocketReady(people[i].sock) ) {
250  HandleClient(i);
251  }
252  }
253  }
254  cleanup(0);
255 
256  /* Not reached, but fixes compiler warnings */
257  return 0;
258 }
259 
DECLSPEC int SDLCALL SDLNet_TCP_Send(TCPsocket sock, const void *data, int len)
Definition: SDLnetTCP.c:236
DECLSPEC int SDLCALL SDLNet_CheckSockets(SDLNet_SocketSet set, Uint32 timeout)
Definition: SDLnetselect.c:110
volatile SDL_bool active
Definition: SDL_events.c:76
Uint32 host
Definition: SDL_net.h:91
int main(int argc, char **argv)
Definition: bootstrap.cpp:102
static SDLNet_SocketSet socketset
Definition: chatd.c:38
#define SDLNet_SocketReady(sock)
Definition: SDL_net.h:347
#define NULL
Definition: ftobjs.h:61
GLclampd n
Definition: glew.h:7287
DECLSPEC void SDLCALL SDLNet_FreeSocketSet(SDLNet_SocketSet set)
Definition: SDLnetselect.c:156
DECLSPEC int SDLCALL SDLNet_Init(void)
Definition: SDLnet.c:86
#define CHAT_ADD_SLOT
Definition: chat.h:41
#define CHAT_ADD_NLEN
Definition: chat.h:44
#define CHAT_DEL_LEN
Definition: chat.h:48
EGLImageKHR EGLint * name
Definition: eglext.h:284
#define CHAT_BYE
Definition: chat.h:49
static struct @98 people[CHAT_MAXPEOPLE]
DECLSPEC void SDLCALL SDL_Quit(void)
Definition: SDL.c:342
DECLSPEC const char *SDLCALL SDL_GetError(void)
Definition: SDL_error.c:204
DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Accept(TCPsocket server)
Definition: SDLnetTCP.c:166
#define CHAT_ADD_HOST
Definition: chat.h:42
DECLSPEC IPaddress *SDLCALL SDLNet_TCP_GetPeerAddress(TCPsocket sock)
Definition: SDLnetTCP.c:223
void SendNew(int about, int to)
Definition: chatd.c:101
#define CHAT_DEL_SLOT
Definition: chat.h:47
#define CHAT_DEL
Definition: chat.h:46
static __inline__ int SDLNet_TCP_AddSocket(SDLNet_SocketSet set, TCPsocket sock)
Definition: SDL_net.h:313
#define CHAT_HELLO_NAME
Definition: chat.h:39
#define CHAT_ADD_PORT
Definition: chat.h:43
struct _SDLNet_SocketSet * SDLNet_SocketSet
Definition: SDL_net.h:298
void HandleServer(void)
Definition: chat.cpp:242
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
IPaddress peer
Definition: chatd.c:42
DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Open(IPaddress *ip)
Definition: SDLnetTCP.c:46
#define CHAT_ADD
Definition: chat.h:40
#define CHAT_HELLO
Definition: chat.h:36
Uint16 port
Definition: SDL_net.h:92
DECLSPEC void SDLCALL SDLNet_Quit(void)
Definition: SDLnet.c:110
void cleanup(int exitcode)
Definition: chat.cpp:339
DECLSPEC int SDLCALL SDLNet_ResolveHost(IPaddress *address, const char *host, Uint16 port)
Definition: SDLnet.c:138
#define CHAT_HELLO_PORT
Definition: chat.h:37
struct _TCPsocket * TCPsocket
Definition: SDL_net.h:131
#define memcpy
Definition: SDL_malloc.c:634
TCPsocket sock
Definition: chatd.c:41
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
static __inline__ int SDLNet_TCP_DelSocket(SDLNet_SocketSet set, TCPsocket sock)
Definition: SDL_net.h:325
#define CHAT_MAXPEOPLE
Definition: chat.h:53
DECLSPEC int SDLCALL SDL_Init(Uint32 flags)
Definition: SDL.c:235
DECLSPEC SDLNet_SocketSet SDLCALL SDLNet_AllocSocketSet(int maxsockets)
Definition: SDLnetselect.c:44
DECLSPEC int SDLCALL SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen)
Definition: SDLnetTCP.c:269
static TCPsocket servsock
Definition: chatd.c:37
int i
Definition: pngrutil.c:1377
#define CHAT_PORT
Definition: chat.h:33
DECLSPEC void SDLCALL SDLNet_TCP_Close(TCPsocket sock)
Definition: SDLnetTCP.c:289
#define CHAT_ADD_NAME
Definition: chat.h:45
DECLSPEC const char *SDLCALL SDLNet_GetError(void)
Definition: SDLnet.c:76
void HandleClient(void)
Definition: chat.cpp:270