root/src/common/socket.c @ 1

Revision 1, 36.5 kB (checked in by jinshiro, 17 years ago)
Line 
1// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
2// For more information, see LICENCE in the main folder
3
4#include "../common/cbasetypes.h"
5#include "../common/mmo.h"
6#include "../common/timer.h"
7#include "../common/malloc.h"
8#include "../common/showmsg.h"
9#include "../common/strlib.h"
10#include "socket.h"
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/types.h>
16
17#ifdef WIN32
18        #include <winsock2.h>
19        #include <io.h>
20#else
21        #include <errno.h>
22        #include <sys/socket.h>
23        #include <netinet/in.h>
24        #include <netinet/tcp.h>
25        #include <net/if.h>
26        #include <unistd.h>
27        #include <sys/time.h>
28        #include <sys/ioctl.h>
29        #include <netdb.h>
30        #include <arpa/inet.h>
31
32        #ifndef SIOCGIFCONF
33        #include <sys/sockio.h> // SIOCGIFCONF on Solaris, maybe others? [Shinomori]
34        #endif
35
36        #ifdef HAVE_SETRLIMIT
37        #include <sys/resource.h>
38        #endif
39#endif
40
41/////////////////////////////////////////////////////////////////////
42#if defined(WIN32)
43/////////////////////////////////////////////////////////////////////
44// windows portability layer
45
46typedef int socklen_t;
47
48#define sErrno WSAGetLastError()
49#define S_ENOTSOCK WSAENOTSOCK
50#define S_EWOULDBLOCK WSAEWOULDBLOCK
51#define S_EINTR WSAEINTR
52#define S_ECONNABORTED WSAECONNABORTED
53
54#define SHUT_RD   SD_RECEIVE
55#define SHUT_WR   SD_SEND
56#define SHUT_RDWR SD_BOTH
57
58// global array of sockets (emulating linux)
59// fd is the position in the array
60static SOCKET sock_arr[FD_SETSIZE];
61static int sock_arr_len = 0;
62
63/// Returns the socket associated with the target fd.
64///
65/// @param fd Target fd.
66/// @return Socket
67#define fd2sock(fd) sock_arr[fd]
68
69/// Returns the first fd associated with the socket.
70/// Returns -1 if the socket is not found.
71///
72/// @param s Socket
73/// @return Fd or -1
74int sock2fd(SOCKET s)
75{
76        int fd;
77
78        // search for the socket
79        for( fd = 1; fd < sock_arr_len; ++fd )
80                if( sock_arr[fd] == s )
81                        break;// found the socket
82        if( fd == sock_arr_len )
83                return -1;// not found
84        return fd;
85}
86
87
88/// Inserts the socket into the global array of sockets.
89/// Returns a new fd associated with the socket.
90/// If there are too many sockets it closes the socket, sets an error and
91//  returns -1 instead.
92/// Since fd 0 is reserved, it returns values in the range [1,FD_SETSIZE[.
93///
94/// @param s Socket
95/// @return New fd or -1
96int sock2newfd(SOCKET s)
97{
98        int fd;
99
100        // find an empty position
101        for( fd = 1; fd < sock_arr_len; ++fd )
102                if( sock_arr[fd] == INVALID_SOCKET )
103                        break;// empty position
104        if( fd == ARRAYLENGTH(sock_arr) )
105        {// too many sockets
106                closesocket(s);
107                WSASetLastError(WSAEMFILE);
108                return -1;
109        }
110        sock_arr[fd] = s;
111        if( sock_arr_len <= fd )
112                sock_arr_len = fd+1;
113        return fd;
114}
115
116int sAccept(int fd, struct sockaddr* addr, int* addrlen)
117{
118        SOCKET s;
119
120        // accept connection
121        s = accept(fd2sock(fd), addr, addrlen);
122        if( s == INVALID_SOCKET )
123                return -1;// error
124        return sock2newfd(s);
125}
126
127int sClose(int fd)
128{
129        int ret = closesocket(fd2sock(fd));
130        fd2sock(fd) = INVALID_SOCKET;
131        return ret;
132}
133
134int sSocket(int af, int type, int protocol)
135{
136        SOCKET s;
137
138        // create socket
139        s = socket(af,type,protocol);
140        if( s == INVALID_SOCKET )
141                return -1;// error
142        return sock2newfd(s);
143}
144
145#define sBind(fd,name,namelen) bind(fd2sock(fd),name,namelen)
146#define sConnect(fd,name,namelen) connect(fd2sock(fd),name,namelen)
147#define sIoctl(fd,cmd,argp) ioctlsocket(fd2sock(fd),cmd,argp)
148#define sListen(fd,backlog) listen(fd2sock(fd),backlog)
149#define sRecv(fd,buf,len,flags) recv(fd2sock(fd),buf,len,flags)
150#define sSelect select
151#define sSend(fd,buf,len,flags) send(fd2sock(fd),buf,len,flags)
152#define sSetsockopt(fd,level,optname,optval,optlen) setsockopt(fd2sock(fd),level,optname,optval,optlen)
153#define sShutdown(fd,how) shutdown(fd2sock(fd),how)
154#define sFD_SET(fd,set) FD_SET(fd2sock(fd),set)
155#define sFD_CLR(fd,set) FD_CLR(fd2sock(fd),set)
156#define sFD_ISSET(fd,set) FD_ISSET(fd2sock(fd),set)
157#define sFD_ZERO FD_ZERO
158
159/////////////////////////////////////////////////////////////////////
160#else
161/////////////////////////////////////////////////////////////////////
162// nix portability layer
163
164#define SOCKET_ERROR (-1)
165
166#define sErrno errno
167#define S_ENOTSOCK EBADF
168#define S_EWOULDBLOCK EAGAIN
169#define S_EINTR EINTR
170#define S_ECONNABORTED ECONNABORTED
171
172#define sAccept accept
173#define sClose close
174#define sSocket socket
175
176#define sBind bind
177#define sConnect connect
178#define sIoctl ioctl
179#define sListen listen
180#define sRecv recv
181#define sSelect select
182#define sSend send
183#define sSetsockopt setsockopt
184#define sShutdown shutdown
185#define sFD_SET FD_SET
186#define sFD_CLR FD_CLR
187#define sFD_ISSET FD_ISSET
188#define sFD_ZERO FD_ZERO
189
190/////////////////////////////////////////////////////////////////////
191#endif
192/////////////////////////////////////////////////////////////////////
193
194fd_set readfds;
195int fd_max;
196time_t last_tick;
197time_t stall_time = 60;
198
199uint32 addr_[16];   // ip addresses of local host (host byte order)
200int naddr_ = 0;   // # of ip addresses
201
202// initial recv buffer size (this will also be the max. size)
203// biggest known packet: S 0153 <len>.w <emblem data>.?B -> 24x24 256 color .bmp (0153 + len.w + 1618/1654/1756 bytes)
204#define RFIFO_SIZE (2*1024)
205// initial send buffer size (will be resized as needed)
206#define WFIFO_SIZE (16*1024)
207
208struct socket_data* session[FD_SETSIZE];
209
210#ifdef SEND_SHORTLIST
211int send_shortlist_array[FD_SETSIZE];// we only support FD_SETSIZE sockets, limit the array to that
212int send_shortlist_count = 0;// how many fd's are in the shortlist
213uint32 send_shortlist_set[(FD_SETSIZE+31)/32];// to know if specific fd's are already in the shortlist
214#endif
215
216static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse);
217
218#ifndef MINICORE
219        int ip_rules = 1;
220        static int connect_check(uint32 ip);
221#endif
222
223
224/*======================================
225 *      CORE : Default processing functions
226 *--------------------------------------*/
227int null_recv(int fd) { return 0; }
228int null_send(int fd) { return 0; }
229int null_parse(int fd) { return 0; }
230
231ParseFunc default_func_parse = null_parse;
232
233void set_defaultparse(ParseFunc defaultparse)
234{
235        default_func_parse = defaultparse;
236}
237
238
239/*======================================
240 *      CORE : Socket options
241 *--------------------------------------*/
242void set_nonblocking(int fd, unsigned long yes)
243{
244        // FIONBIO Use with a nonzero argp parameter to enable the nonblocking mode of socket s.
245        // The argp parameter is zero if nonblocking is to be disabled.
246        if( sIoctl(fd, FIONBIO, &yes) != 0 )
247                ShowError("set_nonblocking: Failed to set socket #%d to non-blocking mode (code %d) - Please report this!!!\n", fd, sErrno);
248}
249
250void setsocketopts(int fd)
251{
252        int yes = 1; // reuse fix
253#if !defined(WIN32)
254        // set SO_REAUSEADDR to true, unix only. on windows this option causes
255        // the previous owner of the socket to give up, which is not desirable
256        // in most cases, neither compatible with unix.
257        sSetsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof(yes));
258#ifdef SO_REUSEPORT
259        sSetsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof(yes));
260#endif
261#endif
262
263        // Set the socket into no-delay mode; otherwise packets get delayed for up to 200ms, likely creating server-side lag.
264        // The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway.
265        sSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes));
266
267        // force the socket into no-wait, graceful-close mode (should be the default, but better make sure)
268        //(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/closesocket_2.asp)
269        {
270        struct linger opt;
271        opt.l_onoff = 0; // SO_DONTLINGER
272        opt.l_linger = 0; // Do not care
273        if( sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&opt, sizeof(opt)) )
274                ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd);
275        }
276}
277
278/*======================================
279 *      CORE : Socket Sub Function
280 *--------------------------------------*/
281void set_eof(int fd)
282{
283        if( session_isActive(fd) )
284        {
285#ifdef SEND_SHORTLIST
286                // Add this socket to the shortlist for eof handling.
287                send_shortlist_add_fd(fd);
288#endif
289                session[fd]->flag.eof = 1;
290        }
291}
292
293int recv_to_fifo(int fd)
294{
295        int len;
296
297        if( !session_isActive(fd) )
298                return -1;
299
300        len = sRecv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0);
301
302        if( len == SOCKET_ERROR )
303        {//An exception has occured
304                if( sErrno != S_EWOULDBLOCK ) {
305                        //ShowDebug("recv_to_fifo: code %d, closing connection #%d\n", sErrno, fd);
306                        set_eof(fd);
307                }
308                return 0;
309        }
310
311        if( len == 0 )
312        {//Normal connection end.
313                set_eof(fd);
314                return 0;
315        }
316
317        session[fd]->rdata_size += len;
318        session[fd]->rdata_tick = last_tick;
319        return 0;
320}
321
322int send_from_fifo(int fd)
323{
324        int len;
325
326        if( !session_isValid(fd) )
327                return -1;
328
329        if( session[fd]->wdata_size == 0 )
330                return 0; // nothing to send
331
332        len = sSend(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, 0);
333
334        if( len == SOCKET_ERROR )
335        {//An exception has occured
336                if( sErrno != S_EWOULDBLOCK ) {
337                        //ShowDebug("send_from_fifo: error %d, ending connection #%d\n", sErrno, fd);
338                        session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex]
339                        set_eof(fd);
340                }
341                return 0;
342        }
343
344        if( len > 0 )
345        {
346                // some data could not be transferred?
347                // shift unsent data to the beginning of the queue
348                if( (size_t)len < session[fd]->wdata_size )
349                        memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len);
350
351                session[fd]->wdata_size -= len;
352        }
353
354        return 0;
355}
356
357/// Best effort - there's no warranty that the data will be sent.
358void flush_fifo(int fd)
359{
360        if(session[fd] != NULL)
361                session[fd]->func_send(fd);
362}
363
364void flush_fifos(void)
365{
366        int i;
367        for(i = 1; i < fd_max; i++)
368                flush_fifo(i);
369}
370
371/*======================================
372 *      CORE : Connection functions
373 *--------------------------------------*/
374int connect_client(int listen_fd)
375{
376        int fd;
377        struct sockaddr_in client_address;
378        socklen_t len;
379
380        len = sizeof(client_address);
381
382        fd = sAccept(listen_fd, (struct sockaddr*)&client_address, &len);
383        if ( fd == -1 ) {
384                ShowError("connect_client: accept failed (code %d)!\n", sErrno);
385                return -1;
386        }
387        if( fd == 0 )
388        {// reserved
389                ShowError("connect_client: Socket #0 is reserved - Please report this!!!\n");
390                sClose(fd);
391                return -1;
392        }
393        if( fd >= FD_SETSIZE )
394        {// socket number too big
395                ShowError("connect_client: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE);
396                sClose(fd);
397                return -1;
398        }
399
400        setsocketopts(fd);
401        set_nonblocking(fd, 1);
402
403#ifndef MINICORE
404        if( ip_rules && !connect_check(ntohl(client_address.sin_addr.s_addr)) ) {
405                do_close(fd);
406                return -1;
407        }
408#endif
409
410        if( fd_max <= fd ) fd_max = fd + 1;
411        sFD_SET(fd,&readfds);
412
413        create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse);
414        session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr);
415
416        return fd;
417}
418
419int make_listen_bind(uint32 ip, uint16 port)
420{
421        struct sockaddr_in server_address;
422        int fd;
423        int result;
424
425        fd = sSocket(AF_INET, SOCK_STREAM, 0);
426
427        if( fd == -1 )
428        {
429                ShowError("make_listen_bind: socket creation failed (code %d)!\n", sErrno);
430                exit(EXIT_FAILURE);
431        }
432        if( fd == 0 )
433        {// reserved
434                ShowError("make_listen_bind: Socket #0 is reserved - Please report this!!!\n");
435                sClose(fd);
436                return -1;
437        }
438        if( fd >= FD_SETSIZE )
439        {// socket number too big
440                ShowError("make_listen_bind: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE);
441                sClose(fd);
442                return -1;
443        }
444
445        setsocketopts(fd);
446        set_nonblocking(fd, 1);
447
448        server_address.sin_family      = AF_INET;
449        server_address.sin_addr.s_addr = htonl(ip);
450        server_address.sin_port        = htons(port);
451
452        result = sBind(fd, (struct sockaddr*)&server_address, sizeof(server_address));
453        if( result == SOCKET_ERROR ) {
454                ShowError("make_listen_bind: bind failed (socket #%d, code %d)!\n", fd, sErrno);
455                exit(EXIT_FAILURE);
456        }
457        result = sListen(fd,5);
458        if( result == SOCKET_ERROR ) {
459                ShowError("make_listen_bind: listen failed (socket #%d, code %d)!\n", fd, sErrno);
460                exit(EXIT_FAILURE);
461        }
462
463        if(fd_max <= fd) fd_max = fd + 1;
464        sFD_SET(fd, &readfds);
465
466        create_session(fd, connect_client, null_send, null_parse);
467        session[fd]->client_addr = 0; // just listens
468        session[fd]->rdata_tick = 0; // disable timeouts on this socket
469
470        return fd;
471}
472
473int make_connection(uint32 ip, uint16 port)
474{
475        struct sockaddr_in remote_address;
476        int fd;
477        int result;
478
479        fd = sSocket(AF_INET, SOCK_STREAM, 0);
480
481        if (fd == -1) {
482                ShowError("make_connection: socket creation failed (code %d)!\n", sErrno);
483                return -1;
484        }
485        if( fd == 0 )
486        {// reserved
487                ShowError("make_connection: Socket #0 is reserved - Please report this!!!\n");
488                sClose(fd);
489                return -1;
490        }
491        if( fd >= FD_SETSIZE )
492        {// socket number too big
493                ShowError("make_connection: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE);
494                sClose(fd);
495                return -1;
496        }
497
498        setsocketopts(fd);
499
500        remote_address.sin_family      = AF_INET;
501        remote_address.sin_addr.s_addr = htonl(ip);
502        remote_address.sin_port        = htons(port);
503
504        ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port);
505
506        result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in));
507        if( result == SOCKET_ERROR ) {
508                ShowError("make_connection: connect failed (socket #%d, code %d)!\n", fd, sErrno);
509                do_close(fd);
510                return -1;
511        }
512        //Now the socket can be made non-blocking. [Skotlex]
513        set_nonblocking(fd, 1);
514
515        if (fd_max <= fd) fd_max = fd + 1;
516        sFD_SET(fd,&readfds);
517
518        create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse);
519        session[fd]->client_addr = ntohl(remote_address.sin_addr.s_addr);
520
521        return fd;
522}
523
524static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse)
525{
526        CREATE(session[fd], struct socket_data, 1);
527        CREATE(session[fd]->rdata, unsigned char, RFIFO_SIZE);
528        CREATE(session[fd]->wdata, unsigned char, WFIFO_SIZE);
529        session[fd]->max_rdata  = RFIFO_SIZE;
530        session[fd]->max_wdata  = WFIFO_SIZE;
531        session[fd]->func_recv  = func_recv;
532        session[fd]->func_send  = func_send;
533        session[fd]->func_parse = func_parse;
534        session[fd]->rdata_tick = last_tick;
535        return 0;
536}
537
538static int delete_session(int fd)
539{
540        if (fd <= 0 || fd >= FD_SETSIZE)
541                return -1;
542        if (session[fd]) {
543                aFree(session[fd]->rdata);
544                aFree(session[fd]->wdata);
545                aFree(session[fd]->session_data);
546                aFree(session[fd]);
547                session[fd] = NULL;
548        }
549        return 0;
550}
551
552int realloc_fifo(int fd, unsigned int rfifo_size, unsigned int wfifo_size)
553{
554        if( !session_isValid(fd) )
555                return 0;
556
557        if( session[fd]->max_rdata != rfifo_size && session[fd]->rdata_size < rfifo_size) {
558                RECREATE(session[fd]->rdata, unsigned char, rfifo_size);
559                session[fd]->max_rdata  = rfifo_size;
560        }
561
562        if( session[fd]->max_wdata != wfifo_size && session[fd]->wdata_size < wfifo_size) {
563                RECREATE(session[fd]->wdata, unsigned char, wfifo_size);
564                session[fd]->max_wdata  = wfifo_size;
565        }
566        return 0;
567}
568
569int realloc_writefifo(int fd, size_t addition)
570{
571        size_t newsize;
572
573        if( !session_isValid(fd) ) // might not happen
574                return 0;
575
576        if( session[fd]->wdata_size + addition  > session[fd]->max_wdata )
577        {       // grow rule; grow in multiples of WFIFO_SIZE
578                newsize = WFIFO_SIZE;
579                while( session[fd]->wdata_size + addition > newsize ) newsize += newsize;
580        }
581        else
582        if( session[fd]->max_wdata >= (size_t)2*(session[fd]->flag.server?FIFOSIZE_SERVERLINK:WFIFO_SIZE)
583                && (session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata )
584        {       // shrink rule, shrink by 2 when only a quarter of the fifo is used, don't shrink below nominal size.
585                newsize = session[fd]->max_wdata / 2;
586        }
587        else // no change
588                return 0;
589
590        RECREATE(session[fd]->wdata, unsigned char, newsize);
591        session[fd]->max_wdata  = newsize;
592
593        return 0;
594}
595
596/// advance the RFIFO cursor (marking 'len' bytes as processed)
597int RFIFOSKIP(int fd, size_t len)
598{
599    struct socket_data *s;
600
601        if ( !session_isActive(fd) )
602                return 0;
603
604        s = session[fd];
605
606        if ( s->rdata_size < s->rdata_pos + len ) {
607                ShowError("RFIFOSKIP: skipped past end of read buffer! Adjusting from %d to %d (session #%d)\n", len, RFIFOREST(fd), fd);
608                len = RFIFOREST(fd);
609        }
610
611        s->rdata_pos = s->rdata_pos + len;
612        return 0;
613}
614
615/// advance the WFIFO cursor (marking 'len' bytes for sending)
616int WFIFOSET(int fd, size_t len)
617{
618        size_t newreserve;
619        struct socket_data* s = session[fd];
620
621        if( !session_isValid(fd) || s->wdata == NULL )
622                return 0;
623
624        // we have written len bytes to the buffer already before calling WFIFOSET
625        if(s->wdata_size+len > s->max_wdata)
626        {       // actually there was a buffer overflow already
627                uint32 ip = s->client_addr;
628                ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %d bytes on a %d/%d bytes buffer.\n", fd, CONVIP(ip), len, s->wdata_size, s->max_wdata);
629                ShowDebug("Likely command that caused it: 0x%x\n", (*(unsigned short*)(s->wdata + s->wdata_size)));
630                // no other chance, make a better fifo model
631                exit(EXIT_FAILURE);
632        }
633
634        s->wdata_size += len;
635        //If the interserver has 200% of its normal size full, flush the data.
636        if( s->flag.server && s->wdata_size >= 2*FIFOSIZE_SERVERLINK )
637                flush_fifo(fd);
638
639        // always keep a WFIFO_SIZE reserve in the buffer
640        // For inter-server connections, let the reserve be 1/4th of the link size.
641        newreserve = s->wdata_size + ( s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE);
642
643        // readjust the buffer to the newly chosen size
644        realloc_writefifo(fd, newreserve);
645
646#ifdef SEND_SHORTLIST
647        send_shortlist_add_fd(fd);
648#endif
649
650        return 0;
651}
652
653int do_sockets(int next)
654{
655        fd_set rfd;
656        struct timeval timeout;
657        int ret,i;
658
659        // PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof.
660        // Send remaining data and process client-side disconnects here.
661#ifdef SEND_SHORTLIST
662        send_shortlist_do_sends();
663#else
664        for (i = 1; i < fd_max; i++)
665        {
666                if(!session[i])
667                        continue;
668
669                if(session[i]->wdata_size)
670                        session[i]->func_send(i);
671        }
672#endif
673
674        // can timeout until the next tick
675        timeout.tv_sec  = next/1000;
676        timeout.tv_usec = next%1000*1000;
677
678        memcpy(&rfd, &readfds, sizeof(rfd));
679        ret = sSelect(fd_max, &rfd, NULL, NULL, &timeout);
680
681        if( ret == SOCKET_ERROR )
682        {
683                if( sErrno != S_EINTR )
684                {
685                        ShowFatalError("do_sockets: select() failed, error code %d!\n", sErrno);
686                        exit(EXIT_FAILURE);
687                }
688                return 0; // interrupted by a signal, just loop and try again
689        }
690
691        last_tick = time(NULL);
692
693#if defined(WIN32)
694        // on windows, enumerating all members of the fd_set is way faster if we access the internals
695        for( i = 0; i < (int)rfd.fd_count; ++i )
696        {
697                int fd = sock2fd(rfd.fd_array[i]);
698                if( session[fd] )
699                        session[fd]->func_recv(fd);
700        }
701#else
702        // otherwise assume that the fd_set is a bit-array and enumerate it in a standard way
703        for( i = 1; ret && i < fd_max; ++i )
704        {
705                if(sFD_ISSET(i,&rfd) && session[i])
706                {
707                        session[i]->func_recv(i);
708                        --ret;
709                }
710        }
711#endif
712
713        // POSTSEND Send remaining data and handle eof sessions.
714#ifdef SEND_SHORTLIST
715        send_shortlist_do_sends();
716#else
717        for (i = 1; i < fd_max; i++)
718        {
719                if(!session[i])
720                        continue;
721
722                if(session[i]->wdata_size)
723                        session[i]->func_send(i);
724
725                if(session[i]->eof) //func_send can't free a session, this is safe.
726                {       //Finally, even if there is no data to parse, connections signalled eof should be closed, so we call parse_func [Skotlex]
727                        session[i]->func_parse(i); //This should close the session immediately.
728                }
729        }
730#endif
731
732        // parse input data on each socket
733        for(i = 1; i < fd_max; i++)
734        {
735                if(!session[i])
736                        continue;
737
738                if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) {
739                        ShowInfo("Session #%d timed out\n", i);
740                        set_eof(i);
741                }
742
743                session[i]->func_parse(i);
744
745                if(!session[i])
746                        continue;
747
748                // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed)
749                if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) {
750                        set_eof(i);
751                        continue;
752                }
753                RFIFOFLUSH(i);
754        }
755
756        return 0;
757}
758
759//////////////////////////////
760#ifndef MINICORE
761//////////////////////////////
762// IP rules and DDoS protection
763
764typedef struct _connect_history {
765        struct _connect_history* next;
766        uint32 ip;
767        uint32 tick;
768        int count;
769        unsigned ddos : 1;
770} ConnectHistory;
771
772typedef struct _access_control {
773        uint32 ip;
774        uint32 mask;
775} AccessControl;
776
777enum _aco {
778        ACO_DENY_ALLOW,
779        ACO_ALLOW_DENY,
780        ACO_MUTUAL_FAILURE
781};
782
783static AccessControl* access_allow = NULL;
784static AccessControl* access_deny = NULL;
785static int access_order    = ACO_DENY_ALLOW;
786static int access_allownum = 0;
787static int access_denynum  = 0;
788static int access_debug    = 0;
789static int ddos_count      = 10;
790static int ddos_interval   = 3*1000;
791static int ddos_autoreset  = 10*60*1000;
792/// Connection history, an array of linked lists.
793/// The array's index for any ip is ip&0xFFFF
794static ConnectHistory* connect_history[0x10000];
795
796static int connect_check_(uint32 ip);
797
798/// Verifies if the IP can connect. (with debug info)
799/// @see connect_check_()
800static int connect_check(uint32 ip)
801{
802        int result = connect_check_(ip);
803        if( access_debug ) {
804                ShowInfo("connect_check: Connection from %d.%d.%d.%d %s\n", CONVIP(ip),result ? "allowed." : "denied!");
805        }
806        return result;
807}
808
809/// Verifies if the IP can connect.
810///  0      : Connection Rejected
811///  1 or 2 : Connection Accepted
812static int connect_check_(uint32 ip)
813{
814        ConnectHistory* hist = connect_history[ip&0xFFFF];
815        int i;
816        int is_allowip = 0;
817        int is_denyip = 0;
818        int connect_ok = 0;
819
820        // Search the allow list
821        for( i=0; i < access_allownum; ++i ){
822                if( (ip & access_allow[i].mask) == (access_allow[i].ip & access_allow[i].mask) ){
823                        if( access_debug ){
824                                ShowInfo("connect_check: Found match from allow list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n",
825                                        CONVIP(ip),
826                                        CONVIP(access_allow[i].ip),
827                                        CONVIP(access_allow[i].mask));
828                        }
829                        is_allowip = 1;
830                        break;
831                }
832        }
833        // Search the deny list
834        for( i=0; i < access_denynum; ++i ){
835                if( (ip & access_deny[i].mask) == (access_deny[i].ip & access_deny[i].mask) ){
836                        if( access_debug ){
837                                ShowInfo("connect_check: Found match from deny list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n",
838                                        CONVIP(ip),
839                                        CONVIP(access_deny[i].ip),
840                                        CONVIP(access_deny[i].mask));
841                        }
842                        is_denyip = 1;
843                        break;
844                }
845        }
846        // Decide connection status
847        //  0 : Reject
848        //  1 : Accept
849        //  2 : Unconditional Accept (accepts even if flagged as DDoS)
850        switch(access_order) {
851        case ACO_DENY_ALLOW:
852        default:
853                if( is_denyip )
854                        connect_ok = 0; // Reject
855                else if( is_allowip )
856                        connect_ok = 2; // Unconditional Accept
857                else
858                        connect_ok = 1; // Accept
859                break;
860        case ACO_ALLOW_DENY:
861                if( is_allowip )
862                        connect_ok = 2; // Unconditional Accept
863                else if( is_denyip )
864                        connect_ok = 0; // Reject
865                else
866                        connect_ok = 1; // Accept
867                break;
868        case ACO_MUTUAL_FAILURE:
869                if( is_allowip && !is_denyip )
870                        connect_ok = 2; // Unconditional Accept
871                else
872                        connect_ok = 0; // Reject
873                break;
874        }
875
876        // Inspect connection history
877        while( hist ) {
878                if( ip == hist->ip )
879                {// IP found
880                        if( hist->ddos )
881                        {// flagged as DDoS
882                                return (connect_ok == 2 ? 1 : 0);
883                        } else if( DIFF_TICK(gettick(),hist->tick) < ddos_interval )
884                        {// connection within ddos_interval
885                                hist->tick = gettick();
886                                if( hist->count++ >= ddos_count )
887                                {// DDoS attack detected
888                                        hist->ddos = 1;
889                                        ShowWarning("connect_check: DDoS Attack detected from %d.%d.%d.%d!\n", CONVIP(ip));
890                                        return (connect_ok == 2 ? 1 : 0);
891                                }
892                                return connect_ok;
893                        } else
894                        {// not within ddos_interval, clear data
895                                hist->tick  = gettick();
896                                hist->count = 0;
897                                return connect_ok;
898                        }
899                }
900                hist = hist->next;
901        }
902        // IP not found, add to history
903        CREATE(hist, ConnectHistory, 1);
904        memset(hist, 0, sizeof(ConnectHistory));
905        hist->ip   = ip;
906        hist->tick = gettick();
907        hist->next = connect_history[ip&0xFFFF];
908        connect_history[ip&0xFFFF] = hist;
909        return connect_ok;
910}
911
912/// Timer function.
913/// Deletes old connection history records.
914static int connect_check_clear(int tid, unsigned int tick, int id, intptr data)
915{
916        int i;
917        int clear = 0;
918        int list  = 0;
919        ConnectHistory root;
920        ConnectHistory* prev_hist;
921        ConnectHistory* hist;
922
923        for( i=0; i < 0x10000 ; ++i ){
924                prev_hist = &root;
925                root.next = hist = connect_history[i];
926                while( hist ){
927                        if( (!hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_interval*3) ||
928                                        (hist->ddos && DIFF_TICK(tick,hist->tick) > ddos_autoreset) )
929                        {// Remove connection history
930                                prev_hist->next = hist->next;
931                                aFree(hist);
932                                hist = prev_hist->next;
933                                clear++;
934                        } else {
935                                prev_hist = hist;
936                                hist = hist->next;
937                        }
938                        list++;
939                }
940                connect_history[i] = root.next;
941        }
942        if( access_debug ){
943                ShowInfo("connect_check_clear: Cleared %d of %d from IP list.\n", clear, list);
944        }
945        return list;
946}
947
948/// Parses the ip address and mask and puts it into acc.
949/// Returns 1 is successful, 0 otherwise.
950int access_ipmask(const char* str, AccessControl* acc)
951{
952        uint32 ip;
953        uint32 mask;
954        unsigned int a[4];
955        unsigned int m[4];
956        int n;
957
958        if( strcmp(str,"all") == 0 ) {
959                ip   = 0;
960                mask = 0;
961        } else {
962                if( ((n=sscanf(str,"%u.%u.%u.%u/%u.%u.%u.%u",a,a+1,a+2,a+3,m,m+1,m+2,m+3)) != 8 && // not an ip + standard mask
963                                (n=sscanf(str,"%u.%u.%u.%u/%u",a,a+1,a+2,a+3,m)) != 5 && // not an ip + bit mask
964                                (n=sscanf(str,"%u.%u.%u.%u",a,a+1,a+2,a+3)) != 4 ) || // not an ip
965                                a[0] > 255 || a[1] > 255 || a[2] > 255 || a[3] > 255 || // invalid ip
966                                (n == 8 && (m[0] > 255 || m[1] > 255 || m[2] > 255 || m[3] > 255)) || // invalid standard mask
967                                (n == 5 && m[0] > 32) ){ // invalid bit mask
968                        return 0;
969                }
970                ip = (uint32)(a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24));
971                if( n == 8 )
972                {// standard mask
973                        mask = (uint32)(a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24));
974                } else if( n == 5 )
975                {// bit mask
976                        mask = 0;
977                        while( m[0] ){
978                                mask = (mask >> 1) | 0x80000000;
979                                --m[0];
980                        }
981                        mask = ntohl(mask);
982                } else
983                {// just this ip
984                        mask = 0xFFFFFFFF;
985                }
986        }
987        if( access_debug ){
988                ShowInfo("access_ipmask: Loaded IP:%d.%d.%d.%d mask:%d.%d.%d.%d\n", CONVIP(ip), CONVIP(mask));
989        }
990        acc->ip   = ip;
991        acc->mask = mask;
992        return 1;
993}
994//////////////////////////////
995#endif
996//////////////////////////////
997
998int socket_config_read(const char* cfgName)
999{
1000        char line[1024],w1[1024],w2[1024];
1001        FILE *fp;
1002
1003        fp = fopen(cfgName, "r");
1004        if(fp == NULL) {
1005                ShowError("File not found: %s\n", cfgName);
1006                return 1;
1007        }
1008
1009        while(fgets(line, sizeof(line), fp))
1010        {
1011                if(line[0] == '/' && line[1] == '/')
1012                        continue;
1013                if(sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
1014                        continue;
1015
1016                if (!strcmpi(w1, "stall_time"))
1017                        stall_time = atoi(w2);
1018#ifndef MINICORE
1019                else if (!strcmpi(w1, "enable_ip_rules")) {
1020                        ip_rules = config_switch(w2);
1021                } else if (!strcmpi(w1, "order")) {
1022                        if (!strcmpi(w2, "deny,allow"))
1023                                access_order = ACO_DENY_ALLOW;
1024                        else if (!strcmpi(w2, "allow,deny"))
1025                                access_order = ACO_ALLOW_DENY;
1026                        else if (!strcmpi(w2, "mutual-failure"))
1027                                access_order = ACO_MUTUAL_FAILURE;
1028                } else if (!strcmpi(w1, "allow")) {
1029                        RECREATE(access_allow, AccessControl, access_allownum+1);
1030                        if (access_ipmask(w2, &access_allow[access_allownum]))
1031                                ++access_allownum;
1032                        else
1033                                ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line);
1034                } else if (!strcmpi(w1, "deny")) {
1035                        RECREATE(access_deny, AccessControl, access_denynum+1);
1036                        if (access_ipmask(w2, &access_deny[access_denynum]))
1037                                ++access_denynum;
1038                        else
1039                                ShowError("socket_config_read: Invalid ip or ip range '%s'!\n", line);
1040                }
1041                else if (!strcmpi(w1,"ddos_interval"))
1042                        ddos_interval = atoi(w2);
1043                else if (!strcmpi(w1,"ddos_count"))
1044                        ddos_count = atoi(w2);
1045                else if (!strcmpi(w1,"ddos_autoreset"))
1046                        ddos_autoreset = atoi(w2);
1047                else if (!strcmpi(w1,"debug"))
1048                        access_debug = config_switch(w2);
1049#endif
1050                else if (!strcmpi(w1, "import"))
1051                        socket_config_read(w2);
1052        }
1053
1054        fclose(fp);
1055        return 0;
1056}
1057
1058
1059void socket_final(void)
1060{
1061        int i;
1062#ifndef MINICORE
1063        ConnectHistory* hist;
1064        ConnectHistory* next_hist;
1065
1066        for( i=0; i < 0x10000; ++i ){
1067                hist = connect_history[i];
1068                while( hist ){
1069                        next_hist = hist->next;
1070                        aFree(hist);
1071                        hist = next_hist;
1072                }
1073        }
1074        if( access_allow )
1075                aFree(access_allow);
1076        if( access_deny )
1077                aFree(access_deny);
1078#endif
1079
1080        for( i = 1; i < fd_max; i++ )
1081                if(session[i])
1082                        do_close(i);
1083
1084        // session[0] ‚̃_ƒ~[ƒf[ƒ^‚ðíœ
1085        aFree(session[0]->rdata);
1086        aFree(session[0]->wdata);
1087        aFree(session[0]);
1088}
1089
1090/// Closes a socket.
1091void do_close(int fd)
1092{
1093        flush_fifo(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket)
1094        sFD_CLR(fd, &readfds);// this needs to be done before closing the socket
1095        sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes
1096        sClose(fd); // We don't really care if these closing functions return an error, we are just shutting down and not reusing this socket.
1097        if (session[fd]) delete_session(fd);
1098}
1099
1100/// Retrieve local ips in host byte order.
1101/// Uses loopback is no address is found.
1102int socket_getips(uint32* ips, int max)
1103{
1104        int num = 0;
1105
1106        if( ips == NULL || max <= 0 )
1107                return 0;
1108
1109#ifdef WIN32
1110        {
1111                char fullhost[255];
1112                u_long** a;
1113                struct hostent* hent;
1114
1115                // XXX This should look up the local IP addresses in the registry
1116                // instead of calling gethostbyname. However, the way IP addresses
1117                // are stored in the registry is annoyingly complex, so I'll leave
1118                // this as T.B.D. [Meruru]
1119                if( gethostname(fullhost, sizeof(fullhost)) == SOCKET_ERROR )
1120                {
1121                        ShowError("socket_getips: No hostname defined!\n");
1122                        return 0;
1123                }
1124                else
1125                {
1126                        hent = gethostbyname(fullhost);
1127                        if( hent == NULL ){
1128                                ShowError("socket_getips: Cannot resolve our own hostname to an IP address\n");
1129                                return 0;
1130                        }
1131                        a = (u_long**)hent->h_addr_list;
1132                        for( ; a[num] != NULL && num < max; ++num)
1133                                ips[num] = (uint32)ntohl(*a[num]);
1134                }
1135        }
1136#else // not WIN32
1137        {
1138                int pos;
1139                int fd;
1140                char buf[2*16*sizeof(struct ifreq)];
1141                struct ifconf ic;
1142                struct ifreq* ir;
1143                struct sockaddr_in* a;
1144                u_long ad;
1145
1146                fd = sSocket(AF_INET, SOCK_STREAM, 0);
1147
1148                memset(buf, 0x00, sizeof(buf));
1149
1150                // The ioctl call will fail with Invalid Argument if there are more
1151                // interfaces than will fit in the buffer
1152                ic.ifc_len = sizeof(buf);
1153                ic.ifc_buf = buf;
1154                if( sIoctl(fd, SIOCGIFCONF, &ic) == -1 )
1155                {
1156                        ShowError("socket_getips: SIOCGIFCONF failed!\n");
1157                        return 0;
1158                }
1159                else
1160                {
1161                        for( pos=0; pos < ic.ifc_len && num < max; )
1162                        {
1163                                ir = (struct ifreq*)(buf+pos);
1164                                a = (struct sockaddr_in*) &(ir->ifr_addr);
1165                                if( a->sin_family == AF_INET ){
1166                                        ad = ntohl(a->sin_addr.s_addr);
1167                                        if( ad != INADDR_LOOPBACK && ad != INADDR_ANY )
1168                                                ips[num++] = (uint32)ad;
1169                                }
1170        #if (defined(BSD) && BSD >= 199103) || defined(_AIX) || defined(__APPLE__)
1171                                pos += ir->ifr_addr.sa_len + sizeof(ir->ifr_name);
1172        #else// not AIX or APPLE
1173                                pos += sizeof(struct ifreq);
1174        #endif//not AIX or APPLE
1175                        }
1176                }
1177                sClose(fd);
1178        }
1179#endif // not W32
1180
1181        // Use loopback if no ips are found
1182        if( num == 0 )
1183                ips[num++] = (uint32)INADDR_LOOPBACK;
1184
1185        return num;
1186}
1187
1188void socket_init(void)
1189{
1190        char *SOCKET_CONF_FILENAME = "conf/packet_athena.conf";
1191
1192#ifdef WIN32
1193        {// Start up windows networking
1194                WSADATA wsaData;
1195                WORD wVersionRequested = MAKEWORD(2, 0);
1196                if( WSAStartup(wVersionRequested, &wsaData) != 0 )
1197                {
1198                        ShowError("socket_init: WinSock not available!\n");
1199                        return;
1200                }
1201                if( LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0 )
1202                {
1203                        ShowError("socket_init: WinSock version mismatch (2.0 or compatible required)!\n");
1204                        return;
1205                }
1206        }
1207#elif defined(HAVE_SETRLIMIT) && !defined(CYGWIN)
1208        // NOTE: getrlimit and setrlimit have bogus behaviour in cygwin.
1209        //       "Number of fds is virtually unlimited in cygwin" (sys/param.h)
1210        {// set socket limit to FD_SETSIZE
1211                struct rlimit rlp;
1212                if( 0 == getrlimit(RLIMIT_NOFILE, &rlp) )
1213                {
1214                        rlp.rlim_cur = FD_SETSIZE;
1215                        if( 0 != setrlimit(RLIMIT_NOFILE, &rlp) )
1216                        {// failed, try setting the maximum too (permission to change system limits is required)
1217                                rlp.rlim_max = FD_SETSIZE;
1218                                if( 0 != setrlimit(RLIMIT_NOFILE, &rlp) )
1219                                {// failed
1220                                        // set to maximum allowed
1221                                        getrlimit(RLIMIT_NOFILE, &rlp);
1222                                        rlp.rlim_cur = rlp.rlim_max;
1223                                        setrlimit(RLIMIT_NOFILE, &rlp);
1224                                        // report limit
1225                                        getrlimit(RLIMIT_NOFILE, &rlp);
1226                                        ShowWarning("socket_init: failed to set socket limit to %d (current limit %d).\n", FD_SETSIZE, (int)rlp.rlim_cur);
1227                                }
1228                        }
1229                }
1230        }
1231#endif
1232
1233        // Get initial local ips
1234        naddr_ = socket_getips(addr_,16);
1235
1236        sFD_ZERO(&readfds);
1237#if defined(SEND_SHORTLIST)
1238        memset(send_shortlist_set, 0, sizeof(send_shortlist_set));
1239#endif
1240
1241        socket_config_read(SOCKET_CONF_FILENAME);
1242
1243        // initialise last send-receive tick
1244        last_tick = time(NULL);
1245
1246        // session[0] is now currently used for disconnected sessions of the map server, and as such,
1247        // should hold enough buffer (it is a vacuum so to speak) as it is never flushed. [Skotlex]
1248        create_session(0, null_recv, null_send, null_parse);
1249
1250#ifndef MINICORE
1251        // Delete old connection history every 5 minutes
1252        memset(connect_history, 0, sizeof(connect_history));
1253        add_timer_func_list(connect_check_clear, "connect_check_clear");
1254        add_timer_interval(gettick()+1000, connect_check_clear, 0, 0, 5*60*1000);
1255#endif
1256}
1257
1258
1259bool session_isValid(int fd)
1260{
1261        return ( fd > 0 && fd < FD_SETSIZE && session[fd] != NULL );
1262}
1263
1264bool session_isActive(int fd)
1265{
1266        return ( session_isValid(fd) && !session[fd]->flag.eof );
1267}
1268
1269// Resolves hostname into a numeric ip.
1270uint32 host2ip(const char* hostname)
1271{
1272        struct hostent* h = gethostbyname(hostname);
1273        return (h != NULL) ? ntohl(*(uint32*)h->h_addr) : 0;
1274}
1275
1276// Converts a numeric ip into a dot-formatted string.
1277// Result is placed either into a user-provided buffer or a static system buffer.
1278const char* ip2str(uint32 ip, char ip_str[16])
1279{
1280        struct in_addr addr;
1281        addr.s_addr = htonl(ip);
1282        return (ip_str == NULL) ? inet_ntoa(addr) : strncpy(ip_str, inet_ntoa(addr), 16);
1283}
1284
1285// Converts a dot-formatted ip string into a numeric ip.
1286uint32 str2ip(const char* ip_str)
1287{
1288        return ntohl(inet_addr(ip_str));
1289}
1290
1291// Reorders bytes from network to little endian (Windows).
1292// Neccessary for sending port numbers to the RO client until Gravity notices that they forgot ntohs() calls.
1293uint16 ntows(uint16 netshort)
1294{
1295        return ((netshort & 0xFF) << 8) | ((netshort & 0xFF00) >> 8);
1296}
1297
1298#ifdef SEND_SHORTLIST
1299// Add a fd to the shortlist so that it'll be recognized as a fd that needs
1300// sending or eof handling.
1301void send_shortlist_add_fd(int fd)
1302{
1303        int i;
1304        int bit;
1305
1306        if( fd < 0 || fd >= FD_SETSIZE )
1307                return;// out of range
1308        i = fd/32;
1309        bit = fd%32;
1310        if( (send_shortlist_set[i]>>bit)&1 )
1311                return;// already in the list
1312
1313        // set the bit
1314        send_shortlist_set[i] |= 1<<bit;
1315        // Add to the end of the shortlist array.
1316        send_shortlist_array[send_shortlist_count++] = fd;
1317}
1318
1319// Do pending network sends and eof handling from the shortlist.
1320void send_shortlist_do_sends()
1321{
1322        int i = 0;
1323
1324        // Assume all or most of the fd's don't remain in the shortlist
1325        memset(send_shortlist_set, 0, sizeof(send_shortlist_set));
1326
1327        while( i < send_shortlist_count )
1328        {
1329                int fd = send_shortlist_array[i];
1330
1331                // If this session still exists, perform send operations on it and
1332                // check for the eof state.
1333                if( session[fd] )
1334                {
1335                        // Send data
1336                        if( session[fd]->wdata_size )
1337                                session[fd]->func_send(fd);
1338
1339                        // If it's been marked as eof, call the parse func on it so that
1340                        // the socket will be immediately closed.
1341                        if( session[fd]->flag.eof )
1342                                session[fd]->func_parse(fd);
1343
1344                        // If the session still exists, is not eof and has things left to
1345                        // be sent from it we'll keep it in the shortlist.
1346                        if( session[fd] && !session[fd]->flag.eof && session[fd]->wdata_size )
1347                        {
1348                                send_shortlist_set[fd/32] |= 1<<(fd%32);
1349                                ++i;
1350                                continue;
1351                        }
1352                }
1353
1354                // Remove fd from shortlist, move the last fd to the current position
1355                send_shortlist_array[i] = send_shortlist_array[--send_shortlist_count];
1356        }
1357}
1358#endif
Note: See TracBrowser for help on using the browser.