5 /*-------------------- Extern Headers Including --------------------*/
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 */
15 #include <windows.h> /* (winsock2 functions) */
16 #define MSG_DONTWAIT 0
20 #include <string.h> /* memcpy */
22 #include <neuro/NEURO.h>
24 /*-------------------- Local Headers Including ---------------------*/
34 /*-------------------- Main Module Header --------------------------*/
37 /*-------------------- Other ----------------------------*/
39 NEURO_MODULE_CHANNEL("netserver");
41 /*-------------------- Global Variables ----------------------------*/
43 /*-------------------- Static Variables ----------------------------*/
45 /*-------------------- Static Prototypes ---------------------------*/
49 /*-------------------- Static Functions ----------------------------*/
52 clean_connection(void *src
)
64 /* 0 is the same, 1 is different */
66 sockaddrCompare(struct sockaddr_in
*a
, struct sockaddr_in
*b
)
69 int size
= sizeof(struct sockaddr_in
);
89 getSlaveByConnectAddr(EBUF
*connections
, struct sockaddr_in
*connect_addr
)
94 if (Neuro_EBufIsEmpty(connections
))
97 total
= Neuro_GiveEBufCount(connections
) + 1;
101 buf
= Neuro_GiveEBuf(connections
, total
);
103 if (!sockaddrCompare(connect_addr
, &buf
->c_address
))
110 /*-------------------- Global Functions ----------------------------*/
113 Server_DisconnectClient(Slave
*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");
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!");
135 connections
= slv
->master
->slave
->cType
.server
->connections
;
137 if (Neuro_EBufIsEmpty(connections
))
141 ce
= slv
->master
->cevents
;
143 /* delete all the remaining events for the slave client, if any */
144 if (!Neuro_EBufIsEmpty(ce
))
149 total
= Neuro_GiveEBufCount(ce
) + 1;
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
))
168 total
= Neuro_GiveEBufCount(slv
->master
->statuses
) + 1;
172 tmp
= Neuro_GiveEBuf(slv
->master
->statuses
, total
);
174 if (tmp
->connection
== slv
)
176 Util_SCleanEBuf(slv
->master
->statuses
, tmp
);
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 */
209 server
= slv
->cType
.server
;
210 sigmask
= slv
->sigmask
;
213 /* only read events are handled for now */
214 if ((sigmask
& 1) != 1)
220 addrlen
= sizeof(struct sockaddr_in
);
222 switch (slv
->master
->protocolType
)
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 */
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
;
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
));
262 char *rbuffer
= NULL
;
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
);
281 /* this is a new client connection, we create a new slave for this. */
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
;
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
));
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
);
326 /*-------------------- Constructor Destructor ----------------------*/
329 Server_Create(Master
*msr
, const char *listen_ip
, int port
)
332 struct sockaddr_in saddress
; /* server address */
334 unsigned int addrlen
= 0;
338 svr
= calloc(1, sizeof(Server
));
340 addrlen
= sizeof(struct sockaddr_in
);
342 sock
= socket(AF_INET
, msr
->protocolType
, 0);
346 ERROR("socket creation failed\n");
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
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
));
369 fcntl(sock
, F_SETFL
, O_NONBLOCK
);
372 unsigned long nb
= 1;
373 if (ioctlsocket(sock
, FIONBIO
, &nb
) == SOCKET_ERROR
)
380 ERROR("binding failed");
394 if (msr
->protocolType
== SOCK_STREAM
)
396 _err
= listen(sock
, 2);
399 ERROR("flagging the master socket as listening failed");
410 Neuro_CreateEBuf(&svr
->connections
);
411 Neuro_SetcallbEBuf(svr
->connections
, clean_connection
);
413 output
= Slave_Create(msr
, sock
, 0, NULL
, svr
);
416 msr
->slave
->c_address
= saddress
;
417 msr
->slave
->addrlen
= sizeof(saddress
);
419 TRACE(Neuro_s("Server is accepting connections on port %d", port
));
425 Server_Destroy(Server
*srv
)
430 Neuro_CleanEBuf(&srv
->connections
);