/************************************************************************** write wrapper function -vasc **************************************************************************/ static int write_socket_data(struct connection *pc, struct socket_packet_buffer *buf, int limit) { int start, nput, nblock; if (is_server() && pc->server.is_closing) { return 0; } for (start=0; buf->ndata-start>limit;) { fd_set writefs, exceptfs; struct timeval tv; FC_FD_ZERO(&writefs); FC_FD_ZERO(&exceptfs); FD_SET(pc->sock, &writefs); FD_SET(pc->sock, &exceptfs); tv.tv_sec = 0; tv.tv_usec = 0; if (fc_select(pc->sock+1, NULL, &writefs, &exceptfs, &tv) <= 0) { if (errno != EINTR) { break; } else { /* EINTR can happen sometimes, especially when compiling with -pg. * Generally we just want to run select again. */ continue; } } if (FD_ISSET(pc->sock, &exceptfs)) { connection_close(pc, _("network exception")); return -1; } if (FD_ISSET(pc->sock, &writefs)) { nblock=MIN(buf->ndata-start, MAX_LEN_PACKET); log_debug("trying to write %d limit=%d", nblock, limit); if((nput=fc_writesocket(pc->sock, (const char *)buf->data+start, nblock)) == -1) { #ifdef NONBLOCKING_SOCKETS if (errno == EWOULDBLOCK || errno == EAGAIN) { break; } #endif connection_close(pc, _("lagging connection")); return -1; } start += nput; } } if (start > 0) { buf->ndata -= start; memmove(buf->data, buf->data+start, buf->ndata); pc->last_write = timer_renew(pc->last_write, TIMER_USER, TIMER_ACTIVE); timer_start(pc->last_write); } return 0; }
/************************************************************************** Check for data received from the metaserver. **************************************************************************/ static enum server_scan_status get_metaserver_list(struct server_scan *scan) { struct timeval tv; fd_set sockset; if (!scan || scan->sock < 0) { return SCAN_STATUS_ERROR; } tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&sockset); FD_SET(scan->sock, &sockset); switch (scan->meta.state) { case META_CONNECTING: if (fc_select(scan->sock + 1, NULL, &sockset, NULL, &tv) < 0) { scan->error_func(scan, fc_strerror(fc_get_errno())); } else if (FD_ISSET(scan->sock, &sockset)) { meta_send_request(scan); } /* Keep waiting. */ return SCAN_STATUS_WAITING; break; case META_WAITING: if (fc_select(scan->sock + 1, &sockset, NULL, NULL, &tv) < 0) { scan->error_func(scan, fc_strerror(fc_get_errno())); } else if (FD_ISSET(scan->sock, &sockset)) { meta_read_response(scan); return SCAN_STATUS_PARTIAL; } /* Keep waiting. */ return SCAN_STATUS_WAITING; break; case META_DONE: return SCAN_STATUS_DONE; break; default: break; } assert(0); return SCAN_STATUS_ERROR; }
/************************************************************************** write wrapper function -vasc **************************************************************************/ static int write_socket_data(struct connection *pc, struct socket_packet_buffer *buf, int limit) { int start, nput, nblock; if (pc->delayed_disconnect) { if (delayed_disconnect > 0) { return 0; } else { if (close_callback) { (*close_callback)(pc); } return -1; } } for (start=0; buf->ndata-start>limit;) { fd_set writefs, exceptfs; struct timeval tv; MY_FD_ZERO(&writefs); MY_FD_ZERO(&exceptfs); FD_SET(pc->sock, &writefs); FD_SET(pc->sock, &exceptfs); tv.tv_sec = 0; tv.tv_usec = 0; if (fc_select(pc->sock+1, NULL, &writefs, &exceptfs, &tv) <= 0) { if (errno != EINTR) { break; } else { /* EINTR can happen sometimes, especially when compiling with -pg. * Generally we just want to run select again. */ continue; } } if (FD_ISSET(pc->sock, &exceptfs)) { if (delayed_disconnect > 0) { pc->delayed_disconnect = TRUE; return 0; } else { if (close_callback) { (*close_callback)(pc); } return -1; } } if (FD_ISSET(pc->sock, &writefs)) { nblock=MIN(buf->ndata-start, MAX_LEN_PACKET); freelog(LOG_DEBUG,"trying to write %d limit=%d",nblock,limit); if((nput=fc_writesocket(pc->sock, (const char *)buf->data+start, nblock)) == -1) { #ifdef NONBLOCKING_SOCKETS if (errno == EWOULDBLOCK || errno == EAGAIN) { break; } #endif if (delayed_disconnect > 0) { pc->delayed_disconnect = TRUE; return 0; } else { if (close_callback) { (*close_callback)(pc); } return -1; } } start += nput; } } if (start > 0) { buf->ndata -= start; memmove(buf->data, buf->data+start, buf->ndata); pc->last_write = renew_timer_start(pc->last_write, TIMER_USER, TIMER_ACTIVE); } return 0; }
/**************************************************************************** A wrapper around read_socket_data() which also handles the case the socket becomes writeable and there is still data which should be sent to the server. Returns: -1 : an error occurred - you should close the socket -2 : the connection was closed >0 : number of bytes read =0 : no data read, would block ****************************************************************************/ static int read_from_connection(struct connection *pc, bool block) { for (;;) { fd_set readfs, writefs, exceptfs; int socket_fd = pc->sock; bool have_data_for_server = (pc->used && pc->send_buffer && 0 < pc->send_buffer->ndata); int n; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; FC_FD_ZERO(&readfs); FD_SET(socket_fd, &readfs); FC_FD_ZERO(&exceptfs); FD_SET(socket_fd, &exceptfs); if (have_data_for_server) { FC_FD_ZERO(&writefs); FD_SET(socket_fd, &writefs); n = fc_select(socket_fd + 1, &readfs, &writefs, &exceptfs, block ? NULL : &tv); } else { n = fc_select(socket_fd + 1, &readfs, NULL, &exceptfs, block ? NULL : &tv); } /* the socket is neither readable, writeable nor got an * exception */ if (n == 0) { return 0; } if (n == -1) { if (errno == EINTR) { /* EINTR can happen sometimes, especially when compiling with -pg. * Generally we just want to run select again. */ log_debug("select() returned EINTR"); continue; } log_error("select() return=%d errno=%d (%s)", n, errno, fc_strerror(fc_get_errno())); return -1; } if (FD_ISSET(socket_fd, &exceptfs)) { return -1; } if (have_data_for_server && FD_ISSET(socket_fd, &writefs)) { flush_connection_send_buffer_all(pc); } if (FD_ISSET(socket_fd, &readfs)) { return read_socket_data(socket_fd, pc->buffer); } } }
/************************************************************************** SDL-client main loop. **************************************************************************/ Uint16 gui_event_loop(void *pData, void (*loop_action)(void *pData), Uint16 (*key_down_handler)(SDL_keysym Key, void *pData), Uint16 (*key_up_handler)(SDL_keysym Key, void *pData), Uint16 (*mouse_button_down_handler)(SDL_MouseButtonEvent *pButtonEvent, void *pData), Uint16 (*mouse_button_up_handler)(SDL_MouseButtonEvent *pButtonEvent, void *pData), Uint16 (*mouse_motion_handler)(SDL_MouseMotionEvent *pMotionEvent, void *pData)) { Uint16 ID; static struct timeval tv; static fd_set civfdset; Uint32 t_current, t_last_unit_anim, t_last_map_scrolling; Uint32 real_timer_next_call; static int result, schot_nr = 0; static char schot[32]; ID = ID_ERROR; t_last_map_scrolling = t_last_unit_anim = real_timer_next_call = SDL_GetTicks(); while (ID == ID_ERROR) { /* ========================================= */ /* net check with 10ms delay event loop */ if ((net_socket >= 0) || (ggz_socket >= 0)) { FD_ZERO(&civfdset); if (net_socket >= 0) { FD_SET(net_socket, &civfdset); } if (ggz_socket >= 0) { FD_SET(ggz_socket, &civfdset); } tv.tv_sec = 0; tv.tv_usec = 10000;/* 10ms*/ result = fc_select(MAX(net_socket, ggz_socket) + 1, &civfdset, NULL, NULL, &tv); if (result < 0) { if (errno != EINTR) { break; } else { continue; } } else { if (result > 0) { if ((net_socket >= 0) && FD_ISSET(net_socket, &civfdset)) { SDL_PushEvent(pNet_User_Event); } if ((ggz_socket >= 0) && FD_ISSET(ggz_socket, &civfdset)) { SDL_PushEvent(pGGZ_User_Event); } } } } else { /* if connection is not establish */ SDL_Delay(10); } /* ========================================= */ t_current = SDL_GetTicks(); if (t_current > real_timer_next_call) { real_timer_next_call = t_current + (real_timer_callback() * 1000); } if ((t_current - t_last_unit_anim) > UNITS_TIMER_INTERVAL) { if (autoconnect) { widget_info_counter++; SDL_PushEvent(pAnim_User_Event); } else { SDL_PushEvent(pAnim_User_Event); } t_last_unit_anim = SDL_GetTicks(); } if (is_map_scrolling) { if ((t_current - t_last_map_scrolling) > MAP_SCROLL_TIMER_INTERVAL) { SDL_PushEvent(pMap_Scroll_User_Event); t_last_map_scrolling = SDL_GetTicks(); } } else { t_last_map_scrolling = SDL_GetTicks(); } if (widget_info_counter > 0) { SDL_PushEvent(pInfo_User_Event); widget_info_counter = 0; } /* ========================================= */ if (loop_action) { loop_action(pData); } /* ========================================= */ while (SDL_PollEvent(&Main.event) == 1) { switch (Main.event.type) { case SDL_QUIT: return MAX_ID; break; case SDL_KEYUP: switch (Main.event.key.keysym.sym) { /* find if Shifts are released */ case SDLK_RSHIFT: RSHIFT = FALSE; break; case SDLK_LSHIFT: LSHIFT = FALSE; break; case SDLK_LCTRL: LCTRL = FALSE; break; case SDLK_RCTRL: RCTRL = FALSE; break; case SDLK_LALT: LALT = FALSE; break; default: if(key_up_handler) { ID = key_up_handler(Main.event.key.keysym, pData); } break; } break; case SDL_KEYDOWN: switch(Main.event.key.keysym.sym) { case SDLK_PRINT: fc_snprintf(schot, sizeof(schot), "fc_%05d.bmp", schot_nr++); log_normal(_("Making screenshot %s"), schot); SDL_SaveBMP(Main.screen, schot); break; case SDLK_RSHIFT: /* Right Shift is Pressed */ RSHIFT = TRUE; break; case SDLK_LSHIFT: /* Left Shift is Pressed */ LSHIFT = TRUE; break; case SDLK_LCTRL: /* Left CTRL is Pressed */ LCTRL = TRUE; break; case SDLK_RCTRL: /* Right CTRL is Pressed */ RCTRL = TRUE; break; case SDLK_LALT: /* Left ALT is Pressed */ LALT = TRUE; break; default: if(key_down_handler) { ID = key_down_handler(Main.event.key.keysym, pData); } break; } break; case SDL_MOUSEBUTTONDOWN: if(mouse_button_down_handler) { ID = mouse_button_down_handler(&Main.event.button, pData); } break; case SDL_MOUSEBUTTONUP: if(mouse_button_up_handler) { ID = mouse_button_up_handler(&Main.event.button, pData); } break; case SDL_MOUSEMOTION: if(mouse_motion_handler) { ID = mouse_motion_handler(&Main.event.motion, pData); } break; case SDL_USEREVENT: switch(Main.event.user.code) { case NET: input_from_server(net_socket); break; case GGZ: input_from_ggz(ggz_socket); break; case ANIM: update_button_hold_state(); animate_mouse_cursor(); draw_mouse_cursor(); break; case SHOW_WIDGET_INFO_LABBEL: draw_widget_info_label(); break; case TRY_AUTO_CONNECT: if (try_to_autoconnect()) { pInfo_User_Event->user.code = SHOW_WIDGET_INFO_LABBEL; autoconnect = FALSE; } break; case FLUSH: unqueue_flush(); break; case MAP_SCROLL: scroll_mapview(scroll_dir); break; case EXIT_FROM_EVENT_LOOP: return MAX_ID; break; default: break; } break; } } if (ID == ID_ERROR) { if (callbacks && callback_list_size(callbacks) > 0) { struct callback *cb = callback_list_get(callbacks, 0); callback_list_remove(callbacks, cb); (cb->callback)(cb->data); free(cb); } } } return ID; }