⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbserver.c

📁 打魔兽战网的都知道他是什么
💻 C
字号:
/* * Copyright (C) 2001		sousou	(liupeng.cs@263.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. */#include "common/setup_before.h"#include "setup.h"#ifdef HAVE_STDDEF_H# include <stddef.h>#else# ifndef NULL#  define NULL ((void *)0)# endif#endif#include <stdio.h>#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 <time.h># include <sys/time.h>#else# ifdef HAVE_SYS_TIME_H#  include <sys/time.h># else#  include <time.h># endif#endif#ifdef HAVE_SYS_TYPES_H# include <sys/types.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#include "compat/inet_ntoa.h"#include "compat/psock.h"#include "common/network.h"#include "dbserver.h"#include "charlock.h"#include "d2ladder.h"#include "dbspacket.h"#include "prefs.h"#include "handle_signal.h"#include "common/list.h"#include "common/eventlog.h"#ifdef WIN32# include <conio.h> /* for kbhit() and getch() */#endif#include "common/addr.h"#include "common/xalloc.h"#include "common/setup_after.h"static int		dbs_packet_gs_id = 0;static t_preset_d2gsid	*preset_d2gsid_head = NULL;t_list * dbs_server_connection_list = NULL;int dbs_server_listen_socket=-1;extern int g_ServiceStatus;/* dbs_server_main * The module's driver function -- we just call other functions and * interpret their results. */static int dbs_handle_timed_events(void);static void dbs_on_exit(void);int dbs_server_init(void);void dbs_server_loop(int ListeningSocket);int dbs_server_setup_fdsets(fd_set * pReadFDs, fd_set * pWriteFDs,        fd_set * pExceptFDs, int ListeningSocket ) ;BOOL dbs_server_read_data(t_d2dbs_connection* conn) ;BOOL dbs_server_write_data(t_d2dbs_connection* conn) ;int dbs_server_list_add_socket(int sd, unsigned int ipaddr);static int setsockopt_keepalive(int sock);static unsigned int get_preset_d2gsid(unsigned int ipaddr);int dbs_server_main(void){	eventlog(eventlog_level_info,__FUNCTION__,"establishing the listener...");	dbs_server_listen_socket = dbs_server_init();	if (dbs_server_listen_socket<0) {		eventlog(eventlog_level_error,__FUNCTION__,"dbs_server_init error ");		return 3;	}	eventlog(eventlog_level_info,__FUNCTION__,"waiting for connections...");	dbs_server_loop(dbs_server_listen_socket);	dbs_on_exit();	return 0;}/* dbs_server_init * Sets up a listener on the given interface and port, returning the * listening socket if successful; if not, returns -1. *//* FIXME: No it doesn't!  pcAddress is not ever referenced in this * function. * CreepLord: Fixed much better way (will accept dns hostnames) */int dbs_server_init(void){	int sd;	struct sockaddr_in sinInterface;	int val;	t_addr	* servaddr;			dbs_server_connection_list=list_create();	if (d2dbs_d2ladder_init()==-1)	{		eventlog(eventlog_level_error,__FUNCTION__,"d2ladder_init() failed");		return -1;	}	if (cl_init(DEFAULT_HASHTBL_LEN, DEFAULT_GS_MAX)==-1)	{		eventlog(eventlog_level_error,__FUNCTION__,"cl_init() failed");		return -1;	}	if (psock_init()<0)	{		eventlog(eventlog_level_error,__FUNCTION__,"psock_init() failed");		return -1;	}		sd = psock_socket(PSOCK_PF_INET, PSOCK_SOCK_STREAM, PSOCK_IPPROTO_TCP);	if (sd==-1)	{		eventlog(eventlog_level_error,__FUNCTION__,"psock_socket() failed : %s",pstrerror(psock_errno()));		return -1;	}	val = 1;	if (psock_setsockopt(sd, PSOCK_SOL_SOCKET, PSOCK_SO_REUSEADDR, &val, sizeof(val)) < 0)	{		eventlog(eventlog_level_error,__FUNCTION__,"psock_setsockopt() failed : %s",pstrerror(psock_errno()));	}        if (!(servaddr=addr_create_str(d2dbs_prefs_get_servaddrs(),INADDR_ANY,DEFAULT_LISTEN_PORT)))	{		eventlog(eventlog_level_error,__FUNCTION__,"could not get servaddr");		return -1;	}		sinInterface.sin_family = PSOCK_AF_INET;	sinInterface.sin_addr.s_addr = htonl(addr_get_ip(servaddr));	sinInterface.sin_port = htons(addr_get_port(servaddr));	if (psock_bind(sd, (struct sockaddr*)&sinInterface, (psock_t_socklen)sizeof(struct sockaddr_in)) < 0)	{		eventlog(eventlog_level_error,__FUNCTION__,"psock_bind() failed : %s",pstrerror(psock_errno()));		return -1;	}	if (psock_listen(sd, LISTEN_QUEUE) < 0)	{		eventlog(eventlog_level_error,__FUNCTION__,"psock_listen() failed : %s",pstrerror(psock_errno()));		return -1;	}	addr_destroy(servaddr);	return sd;}/* dbs_server_setup_fdsets * Set up the three FD sets used with select() with the sockets in the * connection list.  Also add one for the listener socket, if we have * one. */int dbs_server_setup_fdsets(t_psock_fd_set * pReadFDs, t_psock_fd_set * pWriteFDs, t_psock_fd_set * pExceptFDs, int lsocket){	t_elem const * elem;	t_d2dbs_connection* it;	int highest_fd;	PSOCK_FD_ZERO(pReadFDs);	PSOCK_FD_ZERO(pWriteFDs);	PSOCK_FD_ZERO(pExceptFDs); /* FIXME: don't check these... remove this code */	/* Add the listener socket to the read and except FD sets, if there is one. */	if (lsocket >= 0) {		PSOCK_FD_SET(lsocket, pReadFDs);		PSOCK_FD_SET(lsocket, pExceptFDs);	}	highest_fd=lsocket;	LIST_TRAVERSE_CONST(dbs_server_connection_list,elem)	{				if (!(it=elem_get_data(elem))) continue;		if (it->nCharsInReadBuffer < (kBufferSize-kMaxPacketLength)) {			/* There's space in the read buffer, so pay attention to incoming data. */			PSOCK_FD_SET(it->sd, pReadFDs);		}		if (it->nCharsInWriteBuffer > 0) {			PSOCK_FD_SET(it->sd, pWriteFDs);		}		PSOCK_FD_SET(it->sd, pExceptFDs);		if (highest_fd < it->sd) highest_fd=it->sd;	}	return highest_fd;}/* dbs_server_read_data * Data came in on a client socket, so read it into the buffer.  Returns * false on failure, or when the client closes its half of the * connection.  (EAGAIN doesn't count as a failure.) */BOOL dbs_server_read_data(t_d2dbs_connection* conn){	int nBytes;	nBytes = net_recv(conn->sd, conn->ReadBuf + conn->nCharsInReadBuffer,			  kBufferSize - conn->nCharsInReadBuffer);	if (nBytes < 0) return FALSE;	conn->nCharsInReadBuffer += nBytes;	return TRUE;}/* dbs_server_write_data * The connection is writable, so send any pending data.  Returns * false on failure.  (EAGAIN doesn't count as a failure.) */BOOL dbs_server_write_data(t_d2dbs_connection* conn){	int nBytes ;	nBytes = net_send(conn->sd, conn->WriteBuf, 	    conn->nCharsInWriteBuffer > kMaxPacketLength ? kMaxPacketLength : conn->nCharsInWriteBuffer);	if (nBytes < 0) return FALSE;	conn->nCharsInWriteBuffer -= nBytes;	if (conn->nCharsInWriteBuffer)		memmove(conn->WriteBuf, conn->WriteBuf + nBytes, conn->nCharsInWriteBuffer);	return TRUE;}int dbs_server_list_add_socket(int sd, unsigned int ipaddr){	t_d2dbs_connection	*it;	struct in_addr		in;	it=xmalloc(sizeof(t_d2dbs_connection));	memset(it, 0, sizeof(t_d2dbs_connection));	it->sd=sd;	it->ipaddr=ipaddr;	it->major=0;	it->minor=0;	it->type=0;	it->stats=0;	it->verified=0;	it->serverid=get_preset_d2gsid(ipaddr);	it->last_active=time(NULL);	it->nCharsInReadBuffer=0;	it->nCharsInWriteBuffer=0;	list_append_data(dbs_server_connection_list,it);	in.s_addr = htonl(ipaddr);	strncpy(it->serverip, inet_ntoa(in), sizeof(it->serverip)-1);	return 1;}static int dbs_handle_timed_events(void){	static	time_t		prev_ladder_save_time=0;	static	time_t		prev_keepalive_save_time=0;	static  time_t		prev_timeout_checktime=0;	time_t			now;	now=time(NULL);	if (now-prev_ladder_save_time>(signed)prefs_get_laddersave_interval()) {		d2ladder_saveladder();		prev_ladder_save_time=now;	}	if (now-prev_keepalive_save_time>(signed)prefs_get_keepalive_interval()) {		dbs_keepalive();		prev_keepalive_save_time=now;	}	if (now-prev_timeout_checktime>(signed)d2dbs_prefs_get_timeout_checkinterval()) {		dbs_check_timeout();		prev_timeout_checktime=now;	}	return 0;}void dbs_server_loop(int lsocket){	struct sockaddr_in sinRemote;	int sd ;	fd_set ReadFDs, WriteFDs, ExceptFDs;	t_elem * elem;	t_d2dbs_connection* it;	BOOL bOK ;	const char* pcErrorType ;	struct timeval         tv;	int highest_fd;	psock_t_socklen nAddrSize = sizeof(sinRemote);		while (1) {#ifdef WIN32	if (g_ServiceStatus<0 && kbhit() && getch()=='q')	    d2dbs_signal_quit_wrapper();	if (g_ServiceStatus == 0) d2dbs_signal_quit_wrapper();	while (g_ServiceStatus == 2) Sleep(1000);#endif		if (d2dbs_handle_signal()<0) break;		dbs_handle_timed_events();		highest_fd=dbs_server_setup_fdsets(&ReadFDs, &WriteFDs, &ExceptFDs, lsocket);		tv.tv_sec  = 0;		tv.tv_usec = SELECT_TIME_OUT;		switch (psock_select(highest_fd+1, &ReadFDs, &WriteFDs, &ExceptFDs, &tv) ) {			case -1:				eventlog(eventlog_level_error,__FUNCTION__,"psock_select() failed : %s",pstrerror(psock_errno()));				continue;			case 0:				continue;			default:				break;		}		if (PSOCK_FD_ISSET(lsocket, &ReadFDs)) {			sd = psock_accept(lsocket, (struct sockaddr*)&sinRemote, &nAddrSize);			if (sd == -1) {				eventlog(eventlog_level_error,__FUNCTION__,"psock_accept() failed : %s",pstrerror(psock_errno()));				return;			}						eventlog(eventlog_level_info,__FUNCTION__,"accepted connection from %s:%d , socket %d .",				inet_ntoa(sinRemote.sin_addr) , ntohs(sinRemote.sin_port), sd);			eventlog_step(prefs_get_logfile_gs(),eventlog_level_info,__FUNCTION__,"accepted connection from %s:%d , socket %d .",				inet_ntoa(sinRemote.sin_addr) , ntohs(sinRemote.sin_port), sd);			setsockopt_keepalive(sd);			dbs_server_list_add_socket(sd, ntohl(sinRemote.sin_addr.s_addr));			if (psock_ctl(sd,PSOCK_NONBLOCK)<0) {				eventlog(eventlog_level_error,__FUNCTION__,"could not set TCP socket [%d] to non-blocking mode (closing connection) (psock_ctl: %s)", sd,pstrerror(psock_errno()));				psock_close(sd);			}		} else if (PSOCK_FD_ISSET(lsocket, &ExceptFDs)) {			eventlog(eventlog_level_error,__FUNCTION__,"exception on listening socket");			/* FIXME: exceptions are not errors with TCP, they are out-of-band data */			return;		}				LIST_TRAVERSE(dbs_server_connection_list,elem)		{			bOK = TRUE;			pcErrorType = 0;						if (!(it=elem_get_data(elem))) continue;			if (PSOCK_FD_ISSET(it->sd, &ExceptFDs)) {				bOK = FALSE;				pcErrorType = "General socket error"; /* FIXME: no no no no no */				PSOCK_FD_CLR(it->sd, &ExceptFDs);			} else {								if (PSOCK_FD_ISSET(it->sd, &ReadFDs)) {					bOK = dbs_server_read_data(it);					pcErrorType = "Read error";					PSOCK_FD_CLR(it->sd, &ReadFDs);				}								if (PSOCK_FD_ISSET(it->sd, &WriteFDs)) {					bOK = dbs_server_write_data(it);					pcErrorType = "Write error";					PSOCK_FD_CLR(it->sd, &WriteFDs);				}			}						if (!bOK) {				int	err, errno2;				psock_t_socklen	errlen;								err = 0;				errlen = sizeof(err);				errno2 = psock_errno();				if (psock_getsockopt(it->sd, PSOCK_SOL_SOCKET, PSOCK_SO_ERROR, &err, &errlen)==0) {					if (errlen && err!=0) {						err = err ? err : errno2;						eventlog(eventlog_level_error,__FUNCTION__,"data socket error : %s(%d)",pstrerror(err),err);					}				}				dbs_server_shutdown_connection(it);				list_remove_elem(dbs_server_connection_list,&elem);			} else {				if (dbs_packet_handle(it)==-1) {					eventlog(eventlog_level_error,__FUNCTION__,"dbs_packet_handle() failed");					dbs_server_shutdown_connection(it);					list_remove_elem(dbs_server_connection_list,&elem);				}			}		}	}}static void dbs_on_exit(void){	t_elem * elem;	t_d2dbs_connection * it;	if (dbs_server_listen_socket>=0)		psock_close(dbs_server_listen_socket);	dbs_server_listen_socket=-1;	LIST_TRAVERSE(dbs_server_connection_list,elem)	{		if (!(it=elem_get_data(elem))) continue;		dbs_server_shutdown_connection(it);		list_remove_elem(dbs_server_connection_list,&elem);	}	cl_destroy();	d2dbs_d2ladder_destroy();	list_destroy(dbs_server_connection_list);	if (preset_d2gsid_head)	{		t_preset_d2gsid * curr;		t_preset_d2gsid * next;				for (curr=preset_d2gsid_head; curr; curr=next)		{			next = curr->next;			xfree(curr);		}	}	eventlog(eventlog_level_info,__FUNCTION__,"dbserver stopped");}int dbs_server_shutdown_connection(t_d2dbs_connection* conn){	psock_shutdown(conn->sd, PSOCK_SHUT_RDWR) ;	psock_close(conn->sd);	if (conn->verified && conn->type==CONNECT_CLASS_D2GS_TO_D2DBS) {		eventlog(eventlog_level_info,__FUNCTION__,"unlock all characters on gs %s(%d)",conn->serverip,conn->serverid);		eventlog_step(prefs_get_logfile_gs(),eventlog_level_info,__FUNCTION__,"unlock all characters on gs %s(%d)",conn->serverip,conn->serverid);		eventlog_step(prefs_get_logfile_gs(),eventlog_level_info,__FUNCTION__,"close connection to gs on socket %d", conn->sd);		cl_unlock_all_char_by_gsid(conn->serverid);	}	xfree(conn);	return 1;}static int setsockopt_keepalive(int sock){	int		optval;	psock_t_socklen	optlen;	optval = 1;	optlen = sizeof(optval);	if (psock_setsockopt(sock, PSOCK_SOL_SOCKET, PSOCK_SO_KEEPALIVE, &optval, optlen)) {		eventlog(eventlog_level_info,__FUNCTION__,"failed set KEEPALIVE for socket %d, errno=%d", sock, psock_errno());		return -1;	} else {		eventlog(eventlog_level_info,__FUNCTION__,"set KEEPALIVE option for socket %d", sock);		return 0;	}}static unsigned int get_preset_d2gsid(unsigned int ipaddr){	t_preset_d2gsid		*pgsid;	pgsid = preset_d2gsid_head;	while (pgsid)	{		if (pgsid->ipaddr == ipaddr)			return pgsid->d2gsid;		pgsid = pgsid->next;	}	/* not found, build a new item */	pgsid = xmalloc(sizeof(t_preset_d2gsid));	pgsid->ipaddr = ipaddr;	pgsid->d2gsid = ++dbs_packet_gs_id;	/* add to list */	pgsid->next = preset_d2gsid_head;	preset_d2gsid_head = pgsid;	return preset_d2gsid_head->d2gsid;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -