📄 server.c
字号:
/* * Copyright (C) 1998,1999 Mark Baysinger (mbaysing@ucsd.edu) * Copyright (C) 1998,1999,2000,2001 Ross Combs (rocombs@cs.nmsu.edu) * Copyright (C) 2000,2001 Marco Ziech (mmz@gmx.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#define SERVER_INTERNAL_ACCESS#include "common/setup_before.h"#include <stdio.h>#ifdef WIN32# include <conio.h> /* for kbhit() and getch() */#endif#ifdef HAVE_STDDEF_H# include <stddef.h>#else# ifndef NULL# define NULL ((void *)0)# endif#endif#ifdef STDC_HEADERS# include <stdlib.h>#else# ifdef HAVE_MALLOC_H# include <malloc.h># endif#endif#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#ifdef HAVE_FCNTL_H# include <fcntl.h>#else# ifdef HAVE_SYS_FILE_H# include <sys/file.h># endif#endif#ifdef HAVE_STRING_H# include <string.h>#else# ifdef HAVE_STRINGS_H# include <strings.h># endif# ifdef HAVE_MEMORY_H# include <memory.h># endif#endif#include "compat/memset.h"#include <errno.h>#include "compat/strerror.h"#ifdef TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# ifdef HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#include "compat/difftime.h"#ifdef HAVE_SYS_TYPES_H# include <sys/types.h>#endif#ifdef DO_POSIXSIG# include <signal.h># include "compat/signal.h"#endif#ifdef HAVE_SYS_SOCKET_H# include <sys/socket.h>#endif#include "compat/socket.h"#ifdef HAVE_SYS_PARAM_H# include <sys/param.h>#endif#ifdef HAVE_NETINET_IN_H# include <netinet/in.h>#endif#include "compat/netinet_in.h"#ifdef HAVE_ARPA_INET_H# include <arpa/inet.h>#endif#ifdef HAVE_NETDB_H# include <netdb.h>#endif#include "compat/inet_ntoa.h"#include "compat/psock.h"#include "common/packet.h"#include "connection.h"#include "common/hexdump.h"#include "common/eventlog.h"#include "message.h"#include "handle_bnet.h"#include "handle_bot.h"#include "handle_telnet.h"#include "handle_file.h"#include "handle_init.h"#include "handle_d2cs.h"#include "handle_irc.h"#include "handle_udp.h"#include "common/network.h"#include "prefs.h"#include "account.h"#include "common/tracker.h"#include "common/list.h"#include "adbanner.h"#include "timer.h"#include "common/addr.h"#include "common/util.h"#include "common/rlimit.h"#include "ipban.h"#include "helpfile.h"#include "autoupdate.h"#include "versioncheck.h"#include "realm.h"#include "channel.h"#include "game.h"#include "anongame.h"#include "server.h"#include "command_groups.h"#ifdef WIN32# include "win32/service.h"#endif#include "ladder.h"#include "output.h"#include "alias_command.h"#include "anongame_infos.h"#include "news.h"#include "common/fdwatch.h"#include "clan.h"#include "common/trans.h"#include "common/xalloc.h"#include "tournament.h"#include <ctype.h>#include "topic.h"#include "attrlayer.h"#include "cmdline.h"#include "common/setup_after.h"extern FILE * hexstrm; /* from main.c */extern int g_ServiceStatus;#ifdef DO_POSIXSIGstatic void quit_sig_handle(int unused);static void restart_sig_handle(int unused);static void save_sig_handle(int unused);#ifdef HAVE_SETITIMERstatic void timer_sig_handle(int unused);#endif#endiftime_t now;static time_t starttime;static time_t curr_exittime;static volatile time_t sigexittime=0;static volatile int do_restart=0;static volatile int do_save=0;static volatile int got_epipe=0;static char const * server_hostname=NULL;extern void server_quit_delay(int delay){ /* getting negative delay is ok too because it will force immediate * shutdown */ if (delay) sigexittime = time(NULL)+delay; else sigexittime = 0;}extern void server_quit_wraper(void){ if (sigexittime) sigexittime -= prefs_get_shutdown_decr(); else sigexittime = time(NULL)+(time_t)prefs_get_shutdown_delay();}extern void server_restart_wraper(void){ do_restart = 1;}extern void server_save_wraper(void){ do_save = 1;}#ifdef DO_POSIXSIGstatic void quit_sig_handle(int unused){ server_quit_wraper();}static void restart_sig_handle(int unused){ do_restart = 1;}static void save_sig_handle(int unused){ do_save = 1;}static void pipe_sig_handle(int unused){ got_epipe = 1;}#ifdef HAVE_SETITIMERstatic void timer_sig_handle(int unused){ time(&now);}#endifstatic void forced_quit_sig_handle(int unused){ server_quit_delay(-1); /* programs shutdown 1 second before now */}#endifextern unsigned int server_get_uptime(void){ return (unsigned int)difftime(time(NULL),starttime);}extern unsigned int server_get_starttime(void){ return (unsigned int)starttime;}static char const * laddr_type_get_str(t_laddr_type laddr_type){ switch (laddr_type) { case laddr_type_bnet: return "bnet"; case laddr_type_w3route: return "w3route"; case laddr_type_irc: return "irc"; case laddr_type_wol: return "wol"; case laddr_type_telnet: return "telnet"; default: return "UNKNOWN"; }}static int handle_accept(void *data, t_fdwatch_type rw);static int handle_tcp(void *data, t_fdwatch_type rw);static int handle_udp(void *data, t_fdwatch_type rw);static int sd_accept(t_addr const * curr_laddr, t_laddr_info const * laddr_info, int ssocket, int usocket){ char tempa[32]; int csocket; struct sockaddr_in caddr; psock_t_socklen caddr_len; unsigned int raddr; unsigned short rport; if (!addr_get_addr_str(curr_laddr,tempa,sizeof(tempa))) strcpy(tempa,"x.x.x.x:x"); /* accept the connection */ memset(&caddr,0,sizeof(caddr)); /* not sure if this is needed... modern systems are ok anyway */ caddr_len = sizeof(caddr); if ((csocket = psock_accept(ssocket,(struct sockaddr *)&caddr,&caddr_len))<0) { /* BSD, POSIX error for aborted connections, SYSV often uses EAGAIN or EPROTO */ if (#ifdef PSOCK_EWOULDBLOCK psock_errno()==PSOCK_EWOULDBLOCK ||#endif#ifdef PSOCK_ECONNABORTED psock_errno()==PSOCK_ECONNABORTED ||#endif#ifdef PSOCK_EPROTO psock_errno()==PSOCK_EPROTO ||#endif 0) eventlog(eventlog_level_error,__FUNCTION__,"client aborted connection on %s (psock_accept: %s)",tempa,pstrerror(psock_errno())); else /* EAGAIN can mean out of resources _or_ connection aborted :( */ if (#ifdef PSOCK_EINTR psock_errno()!=PSOCK_EINTR &&#endif 1) eventlog(eventlog_level_error,__FUNCTION__,"could not accept new connection on %s (psock_accept: %s)",tempa,pstrerror(psock_errno())); return -1; } /* dont accept new connections while shutdowning */ if (curr_exittime) { psock_shutdown(csocket,PSOCK_SHUT_RDWR); psock_close(csocket); return 0; } if (ipbanlist_check(inet_ntoa(caddr.sin_addr))!=0) { eventlog(eventlog_level_info,__FUNCTION__,"[%d] connection from banned address %s denied (closing connection)",csocket,inet_ntoa(caddr.sin_addr)); psock_close(csocket); return -1; } if ((prefs_get_max_conns_per_IP()!=0) && (connlist_count_connections(ntohl(caddr.sin_addr.s_addr)) > prefs_get_max_conns_per_IP())) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] too many connections from address %s (closing connection)",csocket,inet_ntoa(caddr.sin_addr)); psock_close(csocket); return -1; } eventlog(eventlog_level_info,__FUNCTION__,"[%d] accepted connection from %s on %s",csocket,addr_num_to_addr_str(ntohl(caddr.sin_addr.s_addr),ntohs(caddr.sin_port)),tempa); if (prefs_get_use_keepalive()) { int val=1; if (psock_setsockopt(csocket,PSOCK_SOL_SOCKET,PSOCK_SO_KEEPALIVE,&val,(psock_t_socklen)sizeof(val))<0) eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set socket option SO_KEEPALIVE (psock_setsockopt: %s)",csocket,pstrerror(psock_errno())); /* not a fatal error */ } { struct sockaddr_in rsaddr; psock_t_socklen rlen; memset(&rsaddr,0,sizeof(rsaddr)); /* not sure if this is needed... modern systems are ok anyway */ rlen = sizeof(rsaddr); if (psock_getsockname(csocket,(struct sockaddr *)&rsaddr,&rlen)<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] unable to determine real local port (psock_getsockname: %s)",csocket,pstrerror(psock_errno())); /* not a fatal error */ raddr = addr_get_ip(curr_laddr); rport = addr_get_port(curr_laddr); } else { if (rsaddr.sin_family!=PSOCK_AF_INET) { eventlog(eventlog_level_error,__FUNCTION__,"local address returned with bad address family %d",(int)rsaddr.sin_family); /* not a fatal error */ raddr = addr_get_ip(curr_laddr); rport = addr_get_port(curr_laddr); } else { raddr = ntohl(rsaddr.sin_addr.s_addr); rport = ntohs(rsaddr.sin_port); } } } if (psock_ctl(csocket,PSOCK_NONBLOCK)<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",csocket,pstrerror(psock_errno())); psock_close(csocket); return -1; } { t_connection * c;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -