int do_sockets(fd_set* rfd, int next) { struct timeval timeout; int ret, i; // can timeout until the next tick timeout.tv_sec = next / 1000; timeout.tv_usec = next % 1000 * 1000; memcpy(rfd, &readfds, sizeof(*rfd)); ret = sSelect(fd_max, rfd, nullptr, nullptr, &timeout); if (ret == SOCKET_ERROR) { if (sErrno != S_EINTR) { ShowFatalError("do_sockets: select() failed, error code %d!\n", sErrno); exit(EXIT_FAILURE); } return 0; // interrupted by a signal, just loop and try again } last_tick = time(nullptr); #if defined(WIN32) // on windows, enumerating all members of the fd_set is way faster if we access the internals for (i = 0; i < (int)rfd->fd_count; ++i) { int fd = sock2fd(rfd->fd_array[i]); if (session[fd]) { session[fd]->func_recv(fd); if (fd != login_fd && fd != login_lobbydata_fd && fd != login_lobbyview_fd) { session[fd]->func_parse(fd); if (!session[fd]) continue; // RFIFOFLUSH(fd); } } } #else // otherwise assume that the fd_set is a bit-array and enumerate it in a standard way for (i = 1; ret && i < fd_max; ++i) { if (sFD_ISSET(i, rfd) && session[i]) { session[i]->func_recv(i); if (session[i]) { if (i != login_fd && i != login_lobbydata_fd && i != login_lobbyview_fd) { session[i]->func_parse(i); if (!session[i]) continue; // RFIFOFLUSH(fd); } --ret; } } } #endif /* // parse input data on each socket for(i = 1; i < fd_max; i++) { if(!session[i]) continue; if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) { ShowInfo("Session #%d timed out\n", i); set_eof(i); } session[i]->func_parse(i); if(!session[i]) continue; // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) { set_eof(i); continue; } RFIFOFLUSH(i); }*/ for (i = 1; i < fd_max; i++) { if (!session[i]) continue; if (session[i]->wdata_size) session[i]->func_send(i); } return 0; }
int32 do_sockets(fd_set* rfd, int32 next) { struct timeval timeout; int32 ret; memcpy(rfd, &readfds, sizeof(*rfd)); timeout.tv_sec = next / 1000; timeout.tv_usec = next % 1000 * 1000; ret = sSelect(fd_max, rfd, nullptr, nullptr, &timeout); if (ret == SOCKET_ERROR) { if (sErrno != S_EINTR) { ShowFatalError("do_sockets: select() failed, error code %d!\n", sErrno); do_final(EXIT_FAILURE); } return 0; // interrupted by a signal, just loop and try again } last_tick = time(nullptr); if (sFD_ISSET(map_fd, rfd)) { struct sockaddr_in from; socklen_t fromlen = sizeof(from); int32 ret = recvudp(map_fd, g_PBuff, map_config.buffer_size, 0, (struct sockaddr*)&from, &fromlen); if (ret != -1) { // find player char # ifdef WIN32 uint32 ip = ntohl(from.sin_addr.S_un.S_addr); # else uint32 ip = ntohl(from.sin_addr.s_addr); # endif uint64 port = ntohs(from.sin_port); uint64 ipp = ip; ipp |= port << 32; map_session_data_t* map_session_data = mapsession_getbyipp(ipp); if (map_session_data == nullptr) { map_session_data = mapsession_createsession(ip, ntohs(from.sin_port)); if (map_session_data == nullptr) { map_session_list.erase(ipp); return -1; } } map_session_data->last_update = time(nullptr); size_t size = ret; if (recv_parse(g_PBuff, &size, &from, map_session_data) != -1) { // если предыдущий пакет был потерян, то мы не собираем новый, // а отправляем предыдущий пакет повторно if (!parse(g_PBuff, &size, &from, map_session_data)) { send_parse(g_PBuff, &size, &from, map_session_data); } ret = sendudp(map_fd, g_PBuff, size, 0, (const struct sockaddr*)&from, fromlen); int8* data = g_PBuff; g_PBuff = map_session_data->server_packet_data; map_session_data->server_packet_data = data; map_session_data->server_packet_size = size; } if (map_session_data->shuttingDown > 0) { map_close_session(gettick(), map_session_data); } } } return 0; }