Example #1
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",strerror(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",strerror(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,strerror(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;
				psock_t_socklen	errlen;
				
				err = 0;
				errlen = sizeof(err);
				if (psock_getsockopt(it->sd, PSOCK_SOL_SOCKET, PSOCK_SO_ERROR, &err, &errlen)==0) {
					if (errlen && err!=0) {
						eventlog(eventlog_level_error,__FUNCTION__,"data socket error : %s",strerror(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);
				}
			}
		}
	}
Example #2
0
		/*
			return value:
			1  :  process one or more packet
			0  :  not get a whole packet,do nothing
			-1 :  error
			*/
		extern int dbs_packet_handle(t_d2dbs_connection* conn)
		{
			unsigned short		readlen, writelen;
			t_d2dbs_d2gs_header	* readhead;
			int		retval;

			if (conn->stats == 0) {
				if (conn->nCharsInReadBuffer < (signed)sizeof(t_d2gs_d2dbs_connect)) {
					return 0;
				}
				conn->stats = 1;
				conn->type = conn->ReadBuf[0];

				if (conn->type == CONNECT_CLASS_D2GS_TO_D2DBS) {
					if (dbs_verify_ipaddr(d2dbs_prefs_get_d2gs_list(), conn) < 0) {
						eventlog(eventlog_level_error, __FUNCTION__, "d2gs connection from unknown ip address");
						return -1;
					}
					readlen = 1;
					writelen = 0;
					eventlog(eventlog_level_info, __FUNCTION__, "set connection type for gs %s(%d) on socket %d", conn->serverip, conn->serverid, conn->sd);
					eventlog_step(prefs_get_logfile_gs(), eventlog_level_info, __FUNCTION__, "set connection type for gs %s(%d) on socket %d", conn->serverip, conn->serverid, conn->sd);
				}
				else {
					eventlog(eventlog_level_error, __FUNCTION__, "unknown connection type");
					return -1;
				}
				conn->nCharsInReadBuffer -= readlen;
				std::memmove(conn->ReadBuf, conn->ReadBuf + readlen, conn->nCharsInReadBuffer);
			}
			else if (conn->stats == 1) {
				if (conn->type == CONNECT_CLASS_D2GS_TO_D2DBS) {
					while (conn->nCharsInReadBuffer >= (signed)sizeof(*readhead)) {
						readhead = (t_d2dbs_d2gs_header *)conn->ReadBuf;
						readlen = bn_short_get(readhead->size);
						if (conn->nCharsInReadBuffer < readlen) break;
						switch (bn_short_get(readhead->type)) {
						case D2GS_D2DBS_SAVE_DATA_REQUEST:
							retval = dbs_packet_savedata(conn);
							break;
						case D2GS_D2DBS_GET_DATA_REQUEST:
							retval = dbs_packet_getdata(conn);
							break;
						case D2GS_D2DBS_UPDATE_LADDER:
							retval = dbs_packet_updateladder(conn);
							break;
						case D2GS_D2DBS_CHAR_LOCK:
							retval = dbs_packet_charlock(conn);
							break;
						case D2GS_D2DBS_ECHOREPLY:
							retval = dbs_packet_echoreply(conn);
							break;
						default:
							eventlog(eventlog_level_error, __FUNCTION__, "unknown request type %d", \
								bn_short_get(readhead->type));
							retval = -1;
						}
						if (retval != 1) return retval;
						conn->nCharsInReadBuffer -= readlen;
						std::memmove(conn->ReadBuf, conn->ReadBuf + readlen, conn->nCharsInReadBuffer);
					}
				}
				else {
					eventlog(eventlog_level_error, __FUNCTION__, "unknown connection type %d", conn->type);
					return -1;
				}
			}
			else {
				eventlog(eventlog_level_error, __FUNCTION__, "unknown connection stats");
				return -1;
			}
			return 1;
		}