diff options
Diffstat (limited to 'src/common/socket.c')
-rw-r--r-- | src/common/socket.c | 111 |
1 files changed, 108 insertions, 3 deletions
diff --git a/src/common/socket.c b/src/common/socket.c index efc51b99d..a538f3e31 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -78,6 +78,11 @@ size_t wfifo_size = (16*1024); struct socket_data* session[FD_SETSIZE]; +#ifdef SEND_SHORTLIST +struct send_shortlist_node *send_shortlist = NULL; +fd_set send_shortlist_fd_set; +#endif + int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse); #ifndef MINICORE @@ -148,6 +153,11 @@ void setsocketopts(int fd) *--------------------------------------*/ void set_eof(int fd) { +#ifdef SEND_SHORTLIST + // Add this socket to the shortlist for eof handling. + send_shortlist_add_fd(fd); +#endif + if (session_isActive(fd)) session[fd]->eof = 1; } @@ -495,6 +505,10 @@ int WFIFOSET(int fd, int len) // Even the inter-server buffer may need reallocating! [Skotlex] realloc_writefifo(fd, newreserve); +#ifdef SEND_SHORTLIST + send_shortlist_add_fd(fd); +#endif + return 0; } @@ -509,6 +523,9 @@ int do_sendrecv(int next) //PRESEND Need to do this to ensure that the clients get something to do //which hopefully will cause them to send packets. [Meruru] +#ifdef SEND_SHORTLIST + send_shortlist_do_sends(); +#else for (i = 1; i < fd_max; i++) { if(!session[i]) @@ -517,6 +534,7 @@ int do_sendrecv(int next) if(session[i]->wdata_size) session[i]->func_send(i); } +#endif timeout.tv_sec = next/1000; timeout.tv_usec = next%1000*1000; @@ -549,7 +567,7 @@ int do_sendrecv(int next) { ShowError("Deleting invalid session %d\n", i); //So the code can react accordingly - session[i]->eof = 1; + set_eof(i); session[i]->func_parse(i); delete_session(i); //free the bad session continue; @@ -579,6 +597,9 @@ int do_sendrecv(int next) } #endif +#ifdef SEND_SHORTLIST + send_shortlist_do_sends(); +#else for (i = 1; i < fd_max; i++) { if(!session[i]) @@ -592,6 +613,7 @@ int do_sendrecv(int next) session[i]->func_parse(i); //This should close the session inmediately. } } +#endif return 0; } @@ -606,7 +628,7 @@ int do_parsepacket(void) if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) { ShowInfo ("Session #%d timed out\n", i); - session[i]->eof = 1; + set_eof(i); } session[i]->func_parse(i); @@ -616,7 +638,7 @@ int do_parsepacket(void) /* after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) */ if (session[i]->rdata_size == rfifo_size && session[i]->max_rdata == rfifo_size) { - session[i]->eof = 1; + set_eof(i); continue; } RFIFOFLUSH(i); @@ -1134,3 +1156,86 @@ uint16 ntows(uint16 neshort) { return ((neshort & 0xFF) << 8) | ((neshort & 0xFF00) >> 8); } + +#ifdef SEND_SHORTLIST +// Add a fd to the shortlist so that it'll be recognized as a fd that needs +// sending (or eof handling) done on it. +void send_shortlist_add_fd(int fd) +{ + struct send_shortlist_node* new_node; + + if (FD_ISSET(fd, &send_shortlist_fd_set)) + // Refuse to add duplicate FDs to the shortlist + return; + + new_node = aMalloc(sizeof(*new_node)); + + FD_SET(fd, &send_shortlist_fd_set); + + // Add the new node to the beginning of the shortlist linked list. + new_node->fd = fd; + new_node->prev = NULL; + new_node->next = send_shortlist; + if (new_node->next) + new_node->next->prev = new_node; + + send_shortlist = new_node; +} + +// Do pending network sends (and eof handling) from the shortlist. +void send_shortlist_do_sends() +{ + struct send_shortlist_node + *current_node = send_shortlist, + *next_node; + + while (current_node) + { + int delete_current_node = 1; + + next_node = current_node->next; + + // If this session still exists, perform send operations on it and + // check for the eof state. + if (session[ current_node->fd ]) + { + if (session[ current_node->fd ]->wdata_size) + session[ current_node->fd ]->func_send( current_node->fd ); + + // If it's been marked as eof, call the parse func on it so that + // the socket will be immediately closed. + if (session[ current_node->fd ]->eof) + session[ current_node->fd ]->func_parse( current_node->fd ); + + // If the session still exists, is not eof and has things left to + // be sent from it we'll keep it in the send shortlist. + if (session[ current_node->fd ] && + !session[ current_node->fd ]->eof && + session[ current_node->fd ]->wdata_size) + delete_current_node = 0; + } + + // If this session has been marked for removal from the short list, + // we'll proceed in doing this. + if (delete_current_node) + { + FD_CLR(current_node->fd, &send_shortlist_fd_set); + + // Remove its link entry + if (!current_node->prev) + send_shortlist = next_node; + else + current_node->prev->next = next_node; + + if (current_node->next) + current_node->next->prev = current_node->prev; + + // and free its memory + aFree(current_node); + } + + // Iterate to the next node (session) in the short list + current_node = next_node; + } +} +#endif |