libs/neuronet: Added a lot of debug messages and change a few others.
[neuro.git] / libs / neuronet / server.c
blobb2eac745334f1ee7c7a688d12fab6334e7dd486d
1 /* server.c
2 * Module : Server
3 */
5 /*-------------------- Extern Headers Including --------------------*/
6 #ifndef WIN32
7 #include <sys/socket.h>
8 #include <netinet/in.h> /* htons */
10 #include <fcntl.h> /* fcntl (control of the sockets) */
11 #include <unistd.h> /* close */
13 #else /* WIN32 */
15 #include <windows.h> /* (winsock2 functions) */
16 #define MSG_DONTWAIT 0
18 #endif /* WIN32 */
20 #include <string.h> /* memcpy */
22 #include <neuro/NEURO.h>
24 /*-------------------- Local Headers Including ---------------------*/
25 #include <global.h>
26 #include "common.h"
28 #include "slave.h"
29 #include "master.h"
30 #include "client.h"
31 #include "status.h"
32 #include "util.h"
34 /*-------------------- Main Module Header --------------------------*/
35 #include "server.h"
37 /*-------------------- Other ----------------------------*/
39 NEURO_MODULE_CHANNEL("netserver");
41 /*-------------------- Global Variables ----------------------------*/
43 /*-------------------- Static Variables ----------------------------*/
45 /*-------------------- Static Prototypes ---------------------------*/
49 /*-------------------- Static Functions ----------------------------*/
51 static void
52 clean_connection(void *src)
54 Slave *tmp;
56 tmp = src;
58 if (!tmp)
59 return;
61 Slave_Clean(tmp);
64 /* 0 is the same, 1 is different */
65 static int
66 sockaddrCompare(struct sockaddr_in *a, struct sockaddr_in *b)
68 int i = 0;
69 int size = sizeof(struct sockaddr_in);
70 char *bA, *bB;
72 bA = (char *)a;
73 bB = (char *)b;
75 while( i < size)
77 if (bA[i] == bB[i])
79 i++;
80 continue;
83 return 1;
85 return 0;
88 static Slave *
89 getSlaveByConnectAddr(EBUF *connections, struct sockaddr_in *connect_addr)
91 int total = 0;
92 Slave *buf = NULL;
94 if (Neuro_EBufIsEmpty(connections))
95 return NULL;
97 total = Neuro_GiveEBufCount(connections) + 1;
99 while (total-- > 0)
101 buf = Neuro_GiveEBuf(connections, total);
103 if (!sockaddrCompare(connect_addr, &buf->c_address))
104 return buf;
107 return NULL;
110 /*-------------------- Global Functions ----------------------------*/
112 void
113 Server_DisconnectClient(Slave *slv)
115 EBUF *connections;
116 #if old
117 EBUF *ce;
118 #endif /* old */
120 if (slv)
121 TRACE(Neuro_s("Attempting to disconnect the slave %x", (int)slv));
123 if (!slv || !slv->master || !slv->master->slave)
125 ERROR("Invalid slave trying to be disconnected");
126 return;
129 if (slv->master->slave->cType.server == NULL || slv->master->slave->cType.client == NULL)
131 ERROR("The client attempted to disconnect a client that was already disconnected!");
132 return;
135 connections = slv->master->slave->cType.server->connections;
137 if (Neuro_EBufIsEmpty(connections))
138 return;
140 #if old
141 ce = slv->master->cevents;
143 /* delete all the remaining events for the slave client, if any */
144 if (!Neuro_EBufIsEmpty(ce))
146 int total = 0;
147 Event *tmp;
149 total = Neuro_GiveEBufCount(ce) + 1;
151 while (total-- > 0)
153 tmp = Neuro_GiveEBuf(ce, total);
155 if (tmp->slave == slv)
157 Util_SCleanEBuf(ce, tmp);
162 /* delete all the remaining statuses for the slave client, if any */
163 if (!Neuro_EBufIsEmpty(slv->master->statuses))
165 int total = 0;
166 Status *tmp;
168 total = Neuro_GiveEBufCount(slv->master->statuses) + 1;
170 while (total-- > 0)
172 tmp = Neuro_GiveEBuf(slv->master->statuses, total);
174 if (tmp->connection == slv)
176 Util_SCleanEBuf(slv->master->statuses, tmp);
180 #endif /* old */
182 TRACE(Neuro_s("Disconnected client %x", slv));
184 Status_PurgeSlave(slv->master, slv);
186 Neuro_SCleanEBuf(connections, slv);
189 /*-------------------- Poll ----------------------------------------*/
192 Server_Poll(Slave *slv)
194 struct sockaddr_in connect_addr; /* new connection's address */
195 #ifndef WIN32
196 u32 addrlen = 0;
197 #else /* WIN32 */
198 i32 addrlen = 0;
199 #endif /* WIN32 */
200 i32 _err = 0;
201 int sigmask = 0;
202 Server *server;
204 if (!slv)
206 return 1;
209 server = slv->cType.server;
210 sigmask = slv->sigmask;
212 #if old
213 /* only read events are handled for now */
214 if ((sigmask & 1) != 1)
216 return 0;
218 #endif /* old */
220 addrlen = sizeof(struct sockaddr_in);
222 switch (slv->master->protocolType)
224 case SOCK_STREAM:
226 /* we check to see if theres new clients who want to join the party. */
227 _err = accept(slv->socket, (struct sockaddr*)&connect_addr, &addrlen);
230 /* if theres a new connection, we will add it to our buffer */
231 if (_err != -1)
233 Slave *buf;
234 Client *tmp;
236 /* we have a new client that wishes to connect so we let it connect */
238 Neuro_AllocEBuf(server->connections, sizeof(Slave*), sizeof(Slave));
240 buf = Neuro_GiveCurEBuf(server->connections);
242 tmp = Client_Create(slv->master);
244 tmp->connection_start_time = Neuro_GetTickCount();
245 tmp->idle_time = tmp->connection_start_time;
246 tmp->timeout = 0;
248 Slave_Init(buf, slv->master, _err, 1, tmp, NULL);
250 memcpy(&buf->c_address, &connect_addr, sizeof(struct sockaddr_in));
251 buf->addrlen = addrlen;
253 Status_Add(slv->master, State_NewClient, NULL, 0, buf);
255 TRACE(Neuro_s("New Client Connection %x on socket %d (master %x slave %x)", buf, slv->socket, (int)buf->master, (int)buf));
258 break;
260 case SOCK_DGRAM:
262 char *rbuffer = NULL;
263 #ifndef WIN32
264 ssize_t rbuflen = 0;
265 #else /* WIN32 */
266 int rbuflen = 0;
267 #endif /* WIN32 */
268 int sock;
269 Slave *clientSlv;
271 rbuffer = calloc(1, MAX_PACKET_SIZE * INPUT_PACKET_BUFFERING);
273 rbuflen = recvfrom(slv->socket, rbuffer, MAX_PACKET_SIZE * INPUT_PACKET_BUFFERING, 0, (struct sockaddr*)&connect_addr, &addrlen);
275 TRACE(Neuro_s("Packet from IP %s", inet_ntoa(connect_addr.sin_addr)));
277 clientSlv = getSlaveByConnectAddr(server->connections, &connect_addr);
279 if (!clientSlv)
281 /* this is a new client connection, we create a new slave for this. */
283 Slave *buf;
284 Client *tmp;
286 /* we have a new client that wishes to connect so we let it connect */
288 Neuro_AllocEBuf(server->connections, sizeof(Slave*), sizeof(Slave));
290 buf = Neuro_GiveCurEBuf(server->connections);
292 tmp = Client_Create(slv->master);
294 tmp->connection_start_time = Neuro_GetTickCount();
295 tmp->idle_time = tmp->connection_start_time;
296 tmp->timeout = 0;
298 Slave_Init(buf, slv->master, slv->socket, 1, tmp, NULL);
300 memcpy(&buf->c_address, &connect_addr, sizeof(struct sockaddr_in));
301 buf->addrlen = addrlen;
303 Status_Add(slv->master, State_NewClient, NULL, 0, buf);
305 TRACE(Neuro_s("UDP-> New Client Connection %x on socket %d", buf, slv->socket));
307 clientSlv = buf;
309 else
311 /* we are already connected to this slave, so we just handle its packet */
314 TRACE(Neuro_s("UDP-> Got a new packet of size %d", rbuflen));
316 Util_Buffer_Recv_Data(clientSlv, rbuffer, rbuflen);
318 Client_PopData(clientSlv);
320 break;
323 return 0;
326 /*-------------------- Constructor Destructor ----------------------*/
328 Slave *
329 Server_Create(Master *msr, const char *listen_ip, int port)
331 Slave *output;
332 struct sockaddr_in saddress; /* server address */
333 int _err = 0;
334 unsigned int addrlen = 0;
335 Server *svr;
336 int sock = 0;
338 svr = calloc(1, sizeof(Server));
340 addrlen = sizeof(struct sockaddr_in);
342 sock = socket(AF_INET, msr->protocolType, 0);
344 if (sock <= 0)
346 ERROR("socket creation failed\n");
347 return NULL;
350 #ifndef WIN32
352 int set = 1;
354 /* this should fix an annoying issue happening between the execution
355 * of the server. Bind fails for a while until the address is available
356 * again.
358 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&set, sizeof(int));
360 #endif /* not WIN32 */
362 saddress.sin_family = AF_INET;
363 saddress.sin_addr.s_addr = inet_addr(listen_ip);
364 saddress.sin_port = htons(port);
366 _err = bind(sock, (struct sockaddr*)&saddress, sizeof(saddress));
368 #ifndef WIN32
369 fcntl(sock, F_SETFL, O_NONBLOCK);
370 #else /* WIN32 */
372 unsigned long nb = 1;
373 if (ioctlsocket(sock, FIONBIO, &nb) == SOCKET_ERROR)
374 return NULL;
376 #endif /* WIN32 */
378 if (_err == -1)
380 ERROR("binding failed");
382 free(svr);
384 #ifndef WIN32
385 close(sock);
386 #else /* WIN32 */
387 closesocket(sock);
388 #endif /* WIN32 */
389 return NULL;
392 _err = 0;
394 if (msr->protocolType == SOCK_STREAM)
396 _err = listen(sock, 2);
397 if (_err == -1)
399 ERROR("flagging the master socket as listening failed");
400 #ifndef WIN32
401 close(sock);
402 #else /* WIN32 */
403 closesocket(sock);
404 #endif /* WIN32 */
406 return NULL;
410 Neuro_CreateEBuf(&svr->connections);
411 Neuro_SetcallbEBuf(svr->connections, clean_connection);
413 output = Slave_Create(msr, sock, 0, NULL, svr);
415 msr->slave = output;
416 msr->slave->c_address = saddress;
417 msr->slave->addrlen = sizeof(saddress);
419 TRACE(Neuro_s("Server is accepting connections on port %d", port));
421 return output;
424 void
425 Server_Destroy(Server *srv)
427 if (!srv)
428 return;
430 Neuro_CleanEBuf(&srv->connections);
432 free(srv);