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); } } } }
/* 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; }