static void network_cmd_poll(rarch_cmd_t *handle) { fd_set fds; struct timeval tmp_tv = {0}; if (handle->net_fd < 0) return; FD_ZERO(&fds); FD_SET(handle->net_fd, &fds); if (socket_select(handle->net_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0) return; if (!FD_ISSET(handle->net_fd, &fds)) return; for (;;) { char buf[1024]; ssize_t ret = recvfrom(handle->net_fd, buf, sizeof(buf) - 1, 0, NULL, NULL); if (ret <= 0) break; buf[ret] = '\0'; parse_msg(handle, buf); } }
/*-------------------------------------------------------------------------*\ * Waits for a set of sockets until a condition is met or timeout. \*-------------------------------------------------------------------------*/ static int global_select(lua_State *L) { int rtab, wtab, itab, ret, ndirty; t_socket max_fd; fd_set rset, wset; t_timeout tm; double t = luaL_optnumber(L, 3, -1); FD_ZERO(&rset); FD_ZERO(&wset); lua_settop(L, 3); lua_newtable(L); itab = lua_gettop(L); lua_newtable(L); rtab = lua_gettop(L); lua_newtable(L); wtab = lua_gettop(L); max_fd = collect_fd(L, 1, SOCKET_INVALID, itab, &rset); ndirty = check_dirty(L, 1, rtab, &rset); t = ndirty > 0? 0.0: t; timeout_init(&tm, t, -1); timeout_markstart(&tm); max_fd = collect_fd(L, 2, max_fd, itab, &wset); ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm); if (ret > 0 || ndirty > 0) { return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); return_fd(L, &wset, max_fd+1, itab, wtab, 0); make_assoc(L, rtab); make_assoc(L, wtab); return 2; } else if (ret == 0) { lua_pushstring(L, "timeout"); return 3; } else { lua_pushstring(L, "error"); return 3; } }
char *http_get_status_code( int socket, int timeout ) { char *result = NULL; if( socket_select( socket, timeout ) == 0 ) { return result; } int buffer_length = 24; char *buffer = ( char * )malloc( buffer_length ); if( socket_receive( socket, buffer, buffer_length ) != buffer_length ) { free( buffer ); return result; } result = ( char * )malloc( 4 ); memcpy( result, buffer + 9, 3 ); *( result + 3 ) = '\0'; while( socket_receive( socket, buffer, buffer_length ) == buffer_length ); free( buffer ); return result; }
void socket_buf_clear(UDM_CONN *connp){ char buf[1024]; int len; do { if (socket_select(connp, 0, 'r')==-1) return; len = recv(connp->conn_fd, buf, 1024,0); }while(len > 0); }
static int poll_input(netplay_t *netplay, bool block) { bool had_input = false; int max_fd = netplay->fd + 1; struct timeval tv = {0}; tv.tv_sec = 0; tv.tv_usec = block ? (RETRY_MS * 1000) : 0; do { fd_set fds; /* select() does not take pointer to const struct timeval. * Technically possible for select() to modify tmp_tv, so * we go paranoia mode. */ struct timeval tmp_tv = tv; had_input = false; netplay->timeout_cnt++; FD_ZERO(&fds); FD_SET(netplay->fd, &fds); if (socket_select(max_fd, &fds, NULL, NULL, &tmp_tv) < 0) return -1; if (FD_ISSET(netplay->fd, &fds)) { /* If we're not ready for input, wait until we are. * Could fill the TCP buffer, stalling the other side. */ if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->read_ptr], netplay->read_frame_count)) { had_input = true; if (!netplay_get_cmd(netplay)) return -1; } } /* If we were blocked for input, pass if we have this frame's input */ if (block && netplay->read_frame_count > netplay->self_frame_count) break; /* If we had input, we might have more */ if (had_input || !block) continue; RARCH_LOG("Network is stalling at frame %u, count %u of %d ...\n", netplay->self_frame_count, netplay->timeout_cnt, MAX_RETRIES); if (netplay->timeout_cnt >= MAX_RETRIES && !netplay->remote_paused) return -1; } while (had_input || block); return 0; }
int socket_write(DPS_CONN *connp, const char *buf){ if (socket_select(connp, DPS_NET_READ_TIMEOUT, 'w') == -1) return -1; if (DpsSend(connp->conn_fd, buf, dps_strlen(buf), 0) == -1){ connp->err = DPS_NET_ERROR; return -1; } return 0; }
int socket_write(UDM_CONN *connp, const char *buf){ if (socket_select(connp, UDM_NET_READ_TIMEOUT, 'w') == -1) return -1; if (UdmSend(connp->conn_fd, buf, strlen(buf), 0) == -1){ connp->err = UDM_NET_ERROR; return -1; } return 0; }
static int poll_input(netplay_t *netplay, bool block) { int max_fd = (netplay->fd > netplay->udp_fd ? netplay->fd : netplay->udp_fd) + 1; struct timeval tv = {0}; tv.tv_sec = 0; tv.tv_usec = block ? (RETRY_MS * 1000) : 0; do { fd_set fds; /* select() does not take pointer to const struct timeval. * Technically possible for select() to modify tmp_tv, so * we go paranoia mode. */ struct timeval tmp_tv = tv; netplay->timeout_cnt++; FD_ZERO(&fds); FD_SET(netplay->udp_fd, &fds); FD_SET(netplay->fd, &fds); if (socket_select(max_fd, &fds, NULL, NULL, &tmp_tv) < 0) return -1; /* Somewhat hacky, * but we aren't using the TCP connection for anything useful atm. */ if (FD_ISSET(netplay->fd, &fds) && !netplay_get_cmd(netplay)) return -1; if (FD_ISSET(netplay->udp_fd, &fds)) return 1; if (!block) continue; if (!send_chunk(netplay)) { warn_hangup(); netplay->has_connection = false; return -1; } RARCH_LOG("Network is stalling, resending packet... Count %u of %d ...\n", netplay->timeout_cnt, MAX_RETRIES); } while ((netplay->timeout_cnt < MAX_RETRIES) && block); if (block) return -1; return 0; }
int socket_read( DPS_CONN *connp, size_t maxsize){ int num_read; size_t num_read_total; time_t t; num_read_total = 0; if (connp->buf) DPS_FREE(connp->buf); connp->buf_len_total = 0; connp->buf_len = 0; connp->err = 0; t = time(NULL); do { if (socket_select(connp, connp->timeout, 'r') == -1){ return -1; } if (connp->buf_len_total <= num_read_total+DPS_NET_BUF_SIZE){ connp->buf_len_total += DPS_NET_BUF_SIZE; connp->buf = DpsXrealloc(connp->buf, (size_t)(connp->buf_len_total+1)); if (connp->buf == NULL) return -1; } /* num_read = recv(connp->conn_fd, connp->buf + num_read_total, (DPS_NET_BUF_SIZE <= maxsize - num_read_total) ? DPS_NET_BUF_SIZE : (maxsize - num_read_total), 0);*/ num_read = read(connp->conn_fd, connp->buf + num_read_total, (DPS_NET_BUF_SIZE <= maxsize - num_read_total) ? DPS_NET_BUF_SIZE : (maxsize - num_read_total) ); num_read_total += num_read; if (num_read < 0){ connp->err = DPS_NET_ERROR; return -1; }else if (num_read == 0) { if ((size_t)(time(NULL) - t) > connp->timeout) break; } else t = time(NULL); if (num_read_total >=maxsize ){ connp->err = DPS_NET_FILE_TL; break; } }while (num_read!=0); connp->buf_len = num_read_total; return num_read_total; }
static int global_select(lua_State *L, const sigset_t* mask, int sigreceived) { int rtab, wtab, etab, itab, ret, ndirty; t_socket max_fd; fd_set rset, wset, eset; t_timeout tm; double t = luaL_optnumber(L, 4, -1); FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset); lua_settop(L, 4); lua_newtable(L); itab = lua_gettop(L); lua_newtable(L); rtab = lua_gettop(L); lua_newtable(L); wtab = lua_gettop(L); lua_newtable(L); etab = lua_gettop(L); max_fd = collect_fd(L, 1, SOCKET_INVALID, itab, &rset); ndirty = check_dirty(L, 1, rtab, &rset); t = ndirty > 0? 0.0: t; timeout_init(&tm, t, -1); timeout_markstart(&tm); max_fd = collect_fd(L, 2, max_fd, itab, &wset); max_fd = collect_fd(L, 3, max_fd, itab, &eset); //printf("+enter select\n"); if (sigreceived) { ret = -1; } else { ret = socket_select(max_fd+1, &rset, &wset, &eset, &tm, mask); } //printf("+exit select\n"); if (ret > 0 || ndirty > 0) { return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); return_fd(L, &wset, max_fd+1, itab, wtab, 0); return_fd(L, &eset, max_fd+1, itab, etab, 0); make_assoc(L, rtab); make_assoc(L, wtab); make_assoc(L, etab); return 3; //3 values pushed: 3 result tables } else if (ret == 0) { lua_pushstring(L, "timeout"); return 4; //4 values pushed: 3 result tables + timeout msg } else { lua_pushstring(L, strerror(errno)); return 4; //4 values pushed: 3 result tables + errno msg } }
int Dps_ftp_read_line(DPS_CONN *connp){ if (socket_select(connp, DPS_NET_READ_TIMEOUT, 'r')){ #ifdef DEBUG_FTP fprintf(stderr, "ftp://%s (ftp_read_line-timeout-err): ", connp->hostname); /*DpsLog(connp->indexer, DPS_LOG_DEBUG, "ftp://%s (ftp_read_line-timeout-err): ", connp->hostname);*/ #endif return -1; } do { if (socket_read_line(connp) < 0) return -1; if (((connp->buf[0] =='1')||(connp->buf[0] =='2')|| (connp->buf[0] =='3')||(connp->buf[0] =='4')|| (connp->buf[0] =='5')) && (connp->buf[3] == ' ')) break; }while( 1 ); return 0; }
int main(int argc, char **argv) { t_socket *socket; if (argc < 3) { ft_printf("Usage: client <host> <port>"); return (0); } socket_set_default_read(def_read); socket_set_default_receive(def_receive); socket_set_default_error(def_err); socket = socket_create(); socket_connect(socket, argv[1], ft_atoi(argv[2])); while (1 != 2) { socket_select(socket); } close(socket->fd); return (0); }
int socket_accept(UDM_CONN *connp){ struct sockaddr sa; int sfd; socklen_t len; if (socket_select(connp, UDM_NET_ACC_TIMEOUT, 'r') == -1) return -1; len = sizeof(struct sockaddr); sfd = accept(connp->conn_fd, &sa, &len); socket_close(connp); if (sfd == -1){ connp->err = UDM_NET_ERROR; return -1; } connp->conn_fd = sfd; memcpy(&connp->sin, &sa, sizeof(connp->sin)); return 0; }
int socket_wait_writable(struct mySocket *sock, struct timeval *timeout) { return socket_select(sock, timeout, 0, 1); }
int server_loop(struct command_context *command_context) { struct service *service; bool poll_ok = true; /* used in select() */ fd_set read_fds; int fd_max; /* used in accept() */ int retval; #ifndef _WIN32 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) LOG_ERROR("couldn't set SIGPIPE to SIG_IGN"); #endif while (!shutdown_openocd) { /* monitor sockets for activity */ fd_max = 0; FD_ZERO(&read_fds); /* add service and connection fds to read_fds */ for (service = services; service; service = service->next) { if (service->fd != -1) { /* listen for new connections */ FD_SET(service->fd, &read_fds); if (service->fd > fd_max) fd_max = service->fd; } if (service->connections) { struct connection *c; for (c = service->connections; c; c = c->next) { /* check for activity on the connection */ FD_SET(c->fd, &read_fds); if (c->fd > fd_max) fd_max = c->fd; } } } struct timeval tv; tv.tv_sec = 0; if (poll_ok) { /* we're just polling this iteration, this is faster on embedded * hosts */ tv.tv_usec = 0; retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); } else { /* Every 100ms */ tv.tv_usec = 100000; /* Only while we're sleeping we'll let others run */ openocd_sleep_prelude(); kept_alive(); retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); openocd_sleep_postlude(); } if (retval == -1) { #ifdef _WIN32 errno = WSAGetLastError(); if (errno == WSAEINTR) FD_ZERO(&read_fds); else { LOG_ERROR("error during select: %s", strerror(errno)); exit(-1); } #else if (errno == EINTR) FD_ZERO(&read_fds); else { LOG_ERROR("error during select: %s", strerror(errno)); exit(-1); } #endif } if (retval == 0) { /* We only execute these callbacks when there was nothing to do or we timed *out */ target_call_timer_callbacks(); process_jim_events(command_context); FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */ /* We timed out/there was nothing to do, timeout rather than poll next time **/ poll_ok = false; } else { /* There was something to do, next time we'll just poll */ poll_ok = true; } /* This is a simple back-off algorithm where we immediately * re-poll if we did something this time around. * * This greatly improves performance of DCC. */ poll_ok = poll_ok || target_got_message(); for (service = services; service; service = service->next) { /* handle new connections on listeners */ if ((service->fd != -1) && (FD_ISSET(service->fd, &read_fds))) { if (service->max_connections > 0) add_connection(service, command_context); else { if (service->type == CONNECTION_TCP) { struct sockaddr_in sin; socklen_t address_size = sizeof(sin); int tmp_fd; tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); close_socket(tmp_fd); } LOG_INFO( "rejected '%s' connection, no more connections allowed", service->name); } } /* handle activity on connections */ if (service->connections) { struct connection *c; for (c = service->connections; c; ) { if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) { retval = service->input(c); if (retval != ERROR_OK) { struct connection *next = c->next; if (service->type == CONNECTION_PIPE) { /* if connection uses a pipe then *shutdown openocd on error */ shutdown_openocd = 1; } remove_connection(service, c); LOG_INFO("dropped '%s' connection", service->name); c = next; continue; } } c = c->next; } } } #ifdef _WIN32 MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) shutdown_openocd = 1; } #endif } return ERROR_OK; }
/** * netplay_sync_pre_frame * @netplay : pointer to netplay object * * Pre-frame for Netplay synchronization. */ bool netplay_sync_pre_frame(netplay_t *netplay) { retro_ctx_serialize_info_t serial_info; if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->run_ptr], netplay->run_frame_count)) { serial_info.data_const = NULL; serial_info.data = netplay->buffer[netplay->run_ptr].state; serial_info.size = netplay->state_size; memset(serial_info.data, 0, serial_info.size); if ((netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) || netplay->run_frame_count == 0) { /* Don't serialize until it's safe */ } else if (!(netplay->quirks & NETPLAY_QUIRK_NO_SAVESTATES) && core_serialize(&serial_info)) { if (netplay->force_send_savestate && !netplay->stall && !netplay->remote_paused) { /* Bring our running frame and input frames into parity so we don't * send old info */ if (netplay->run_ptr != netplay->self_ptr) { memcpy(netplay->buffer[netplay->self_ptr].state, netplay->buffer[netplay->run_ptr].state, netplay->state_size); netplay->run_ptr = netplay->self_ptr; netplay->run_frame_count = netplay->self_frame_count; } /* Send this along to the other side */ serial_info.data_const = netplay->buffer[netplay->run_ptr].state; netplay_load_savestate(netplay, &serial_info, false); netplay->force_send_savestate = false; } } else { /* If the core can't serialize properly, we must stall for the * remote input on EVERY frame, because we can't recover */ netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; netplay->stateless_mode = true; } /* If we can't transmit savestates, we must stall until the client is ready */ if (netplay->run_frame_count > 0 && (netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION)) && (netplay->connections_size == 0 || !netplay->connections[0].active || netplay->connections[0].mode < NETPLAY_CONNECTION_CONNECTED)) netplay->stall = NETPLAY_STALL_NO_CONNECTION; } if (netplay->is_server) { fd_set fds; struct timeval tmp_tv = {0}; int new_fd; struct sockaddr_storage their_addr; socklen_t addr_size; struct netplay_connection *connection; size_t connection_num; /* Check for a connection */ FD_ZERO(&fds); FD_SET(netplay->listen_fd, &fds); if (socket_select(netplay->listen_fd + 1, &fds, NULL, NULL, &tmp_tv) > 0 && FD_ISSET(netplay->listen_fd, &fds)) { addr_size = sizeof(their_addr); new_fd = accept(netplay->listen_fd, (struct sockaddr*)&their_addr, &addr_size); if (new_fd < 0) { RARCH_ERR("%s\n", msg_hash_to_str(MSG_NETPLAY_FAILED)); goto process; } /* Set the socket nonblocking */ if (!socket_nonblock(new_fd)) { /* Catastrophe! */ socket_close(new_fd); goto process; } #if defined(IPPROTO_TCP) && defined(TCP_NODELAY) { int flag = 1; if (setsockopt(new_fd, IPPROTO_TCP, TCP_NODELAY, #ifdef _WIN32 (const char*) #else (const void*) #endif &flag, sizeof(int)) < 0) RARCH_WARN("Could not set netplay TCP socket to nodelay. Expect jitter.\n"); } #endif #if defined(F_SETFD) && defined(FD_CLOEXEC) /* Don't let any inherited processes keep open our port */ if (fcntl(new_fd, F_SETFD, FD_CLOEXEC) < 0) RARCH_WARN("Cannot set Netplay port to close-on-exec. It may fail to reopen if the client disconnects.\n"); #endif /* Allocate a connection */ for (connection_num = 0; connection_num < netplay->connections_size; connection_num++) if (!netplay->connections[connection_num].active && netplay->connections[connection_num].mode != NETPLAY_CONNECTION_DELAYED_DISCONNECT) break; if (connection_num == netplay->connections_size) { if (connection_num == 0) { netplay->connections = (struct netplay_connection*)malloc(sizeof(struct netplay_connection)); if (netplay->connections == NULL) { socket_close(new_fd); goto process; } netplay->connections_size = 1; } else { size_t new_connections_size = netplay->connections_size * 2; struct netplay_connection *new_connections = (struct netplay_connection*) realloc(netplay->connections, new_connections_size*sizeof(struct netplay_connection)); if (new_connections == NULL) { socket_close(new_fd); goto process; } memset(new_connections + netplay->connections_size, 0, netplay->connections_size * sizeof(struct netplay_connection)); netplay->connections = new_connections; netplay->connections_size = new_connections_size; } } connection = &netplay->connections[connection_num]; /* Set it up */ memset(connection, 0, sizeof(*connection)); connection->active = true; connection->fd = new_fd; connection->mode = NETPLAY_CONNECTION_INIT; if (!netplay_init_socket_buffer(&connection->send_packet_buffer, netplay->packet_buffer_size) || !netplay_init_socket_buffer(&connection->recv_packet_buffer, netplay->packet_buffer_size)) { if (connection->send_packet_buffer.data) netplay_deinit_socket_buffer(&connection->send_packet_buffer); connection->active = false; socket_close(new_fd); goto process; } netplay_handshake_init_send(netplay, connection); } } process: netplay->can_poll = true; input_poll_net(); return (netplay->stall != NETPLAY_STALL_NO_CONNECTION); }
static bool netplay_lan_ad_client(void) { fd_set fds; socklen_t addr_size; struct sockaddr their_addr; struct timeval tmp_tv = {0}; if (lan_ad_client_fd < 0) return false; /* Check for any ad queries */ while (1) { FD_ZERO(&fds); FD_SET(lan_ad_client_fd, &fds); if (socket_select(lan_ad_client_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0) break; if (!FD_ISSET(lan_ad_client_fd, &fds)) break; /* Somebody queried, so check that it's valid */ addr_size = sizeof(their_addr); if (recvfrom(lan_ad_client_fd, (char*)&ad_packet_buffer, sizeof(struct ad_packet), 0, &their_addr, &addr_size) >= (ssize_t) sizeof(struct ad_packet)) { struct netplay_host *host = NULL; /* Make sure it's a valid response */ if (memcmp((void *) &ad_packet_buffer, "RANS", 4)) continue; /* For this version */ if (ntohl(ad_packet_buffer.protocol_version) != NETPLAY_PROTOCOL_VERSION) continue; /* And that we know how to handle it */ if (their_addr.sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *) &their_addr; sin->sin_port = htons(ntohl(ad_packet_buffer.port)); } #ifdef HAVE_INET6 else if (their_addr.sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &their_addr; sin6->sin6_port = htons(ad_packet_buffer.port); } #endif else continue; /* Allocate space for it */ if (discovered_hosts.size >= discovered_hosts_allocated) { size_t allocated = discovered_hosts_allocated; struct netplay_host *new_hosts = NULL; if (allocated == 0) allocated = 2; else allocated *= 2; if (discovered_hosts.hosts) new_hosts = (struct netplay_host *) realloc(discovered_hosts.hosts, allocated * sizeof(struct netplay_host)); else /* Should be equivalent to realloc, but I don't trust screwy libcs */ new_hosts = (struct netplay_host *) malloc(allocated * sizeof(struct netplay_host)); if (!new_hosts) return false; discovered_hosts.hosts = new_hosts; discovered_hosts_allocated = allocated; } /* Get our host structure */ host = &discovered_hosts.hosts[discovered_hosts.size++]; /* Copy in the response */ memset(host, 0, sizeof(struct netplay_host)); host->addr = their_addr; host->addrlen = addr_size; strlcpy(host->nick, ad_packet_buffer.nick, NETPLAY_HOST_STR_LEN); strlcpy(host->core, ad_packet_buffer.core, NETPLAY_HOST_STR_LEN); strlcpy(host->core_version, ad_packet_buffer.core_version, NETPLAY_HOST_STR_LEN); strlcpy(host->content, ad_packet_buffer.content, NETPLAY_HOST_LONGSTR_LEN); host->content_crc = atoi(ad_packet_buffer.content_crc); host->nick[NETPLAY_HOST_STR_LEN-1] = host->core[NETPLAY_HOST_STR_LEN-1] = host->core_version[NETPLAY_HOST_STR_LEN-1] = host->content[NETPLAY_HOST_LONGSTR_LEN-1] = '\0'; } } return true; }
/** * netplay_pre_frame: * @netplay : pointer to netplay object * * Pre-frame for Netplay. * Call this before running retro_run(). * * Returns: true (1) if the frontend is cleared to emulate the frame, false (0) * if we're stalled or paused **/ bool netplay_pre_frame(netplay_t *netplay) { bool sync_stalled; settings_t *settings = config_get_ptr(); retro_assert(netplay); if (settings->bools.netplay_public_announce) { reannounce++; if ((netplay->is_server || is_mitm) && (reannounce % 600 == 0)) netplay_announce(); } else { /* Make sure that if announcement is turned on mid-game, it gets announced */ reannounce = -1; } /* FIXME: This is an ugly way to learn we're not paused anymore */ if (netplay->local_paused) netplay_frontend_paused(netplay, false); if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) { /* Are we ready now? */ netplay_try_init_serialization(netplay); } if (netplay->is_server && !settings->bools.netplay_use_mitm_server) { /* Advertise our server */ netplay_lan_ad_server(netplay); /* NAT traversal if applicable */ if (netplay->nat_traversal && !netplay->nat_traversal_task_oustanding && netplay->nat_traversal_state.request_outstanding && !netplay->nat_traversal_state.have_inet4) { struct timeval tmptv = {0}; fd_set fds = netplay->nat_traversal_state.fds; if (socket_select(netplay->nat_traversal_state.nfds, &fds, NULL, NULL, &tmptv) > 0) natt_read(&netplay->nat_traversal_state); #ifndef HAVE_SOCKET_LEGACY if (!netplay->nat_traversal_state.request_outstanding || netplay->nat_traversal_state.have_inet4) netplay_announce_nat_traversal(netplay); #endif } } sync_stalled = !netplay_sync_pre_frame(netplay); /* If we're disconnected, deinitialize */ if (!netplay->is_server && !netplay->connections[0].active) { netplay_disconnect(netplay); return true; } if (sync_stalled || ((!netplay->is_server || (netplay->connected_players>1)) && (netplay->stall || netplay->remote_paused))) { /* We may have received data even if we're stalled, so run post-frame * sync */ netplay_sync_post_frame(netplay, true); return false; } return true; }
bool netplay_ad_server(netplay_t *netplay, int ad_fd) { fd_set fds; struct timeval tmp_tv = {0}; struct sockaddr their_addr; socklen_t addr_size; rarch_system_info_t *info = NULL; size_t bufloc; if (!ad_packet_buffer) { ad_packet_buffer = (uint32_t *) malloc(AD_PACKET_MAX_SIZE); if (!ad_packet_buffer) return false; } /* Check for any ad queries */ while (1) { FD_ZERO(&fds); FD_SET(ad_fd, &fds); if (socket_select(ad_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0) break; if (!FD_ISSET(ad_fd, &fds)) break; /* Somebody queried, so check that it's valid */ if (recvfrom(ad_fd, (char*)ad_packet_buffer, AD_PACKET_MAX_SIZE, 0, &their_addr, &addr_size) >= (ssize_t) (2*sizeof(uint32_t))) { /* Make sure it's a valid query */ if (memcmp(ad_packet_buffer, "RANQ", 4)) continue; /* For this version */ if (ntohl(ad_packet_buffer[1]) != NETPLAY_PROTOCOL_VERSION) continue; runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &info); /* Now build our response */ memset(ad_packet_buffer, 0, AD_PACKET_MAX_SIZE); memcpy(ad_packet_buffer, "RANS", 4); ad_packet_buffer[1] = htonl(NETPLAY_PROTOCOL_VERSION); ad_packet_buffer[2] = htonl(netplay->tcp_port); bufloc = 3; strncpy((char *) (ad_packet_buffer + bufloc), PACKAGE_VERSION, AD_PACKET_STRING_SIZE); bufloc += AD_PACKET_STRING_WORDS; strncpy((char *) (ad_packet_buffer + bufloc), netplay->nick, AD_PACKET_STRING_SIZE); bufloc += AD_PACKET_STRING_WORDS; if (info) { strncpy((char *) (ad_packet_buffer + bufloc), info->info.library_name, AD_PACKET_STRING_SIZE); bufloc += AD_PACKET_STRING_WORDS; strncpy((char *) (ad_packet_buffer + bufloc), info->info.library_version, AD_PACKET_STRING_SIZE); bufloc += AD_PACKET_STRING_WORDS; /* Blank content */ bufloc += AD_PACKET_STRING_WORDS; } else { bufloc += 3*AD_PACKET_STRING_WORDS; } /* And send it */ sendto(ad_fd, (const char*)ad_packet_buffer, bufloc*sizeof(uint32_t), 0, &their_addr, addr_size); } } return true; }
/** * netplay_lan_ad_server * * Respond to any LAN ad queries that the netplay server has received. */ bool netplay_lan_ad_server(netplay_t *netplay) { fd_set fds; struct timeval tmp_tv = {0}; struct sockaddr their_addr; socklen_t addr_size; rarch_system_info_t *info = NULL; if (lan_ad_server_fd < 0 && !init_lan_ad_server_socket(netplay, RARCH_DEFAULT_PORT)) return false; /* Check for any ad queries */ while (1) { FD_ZERO(&fds); FD_SET(lan_ad_server_fd, &fds); if (socket_select(lan_ad_server_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0) break; if (!FD_ISSET(lan_ad_server_fd, &fds)) break; /* Somebody queried, so check that it's valid */ addr_size = sizeof(their_addr); if (recvfrom(lan_ad_server_fd, (char*)&ad_packet_buffer, sizeof(struct ad_packet), 0, &their_addr, &addr_size) >= (ssize_t) (2*sizeof(uint32_t))) { char s[NETPLAY_HOST_STR_LEN]; uint32_t content_crc = 0; /* Make sure it's a valid query */ if (memcmp((void *) &ad_packet_buffer, "RANQ", 4)) continue; /* For this version */ if (ntohl(ad_packet_buffer.protocol_version) != NETPLAY_PROTOCOL_VERSION) continue; info = runloop_get_system_info(); /* Now build our response */ content_crc = content_get_crc(); memset(&ad_packet_buffer, 0, sizeof(struct ad_packet)); memcpy(&ad_packet_buffer, "RANS", 4); ad_packet_buffer.protocol_version = htonl(NETPLAY_PROTOCOL_VERSION); ad_packet_buffer.port = htonl(netplay->tcp_port); strlcpy(ad_packet_buffer.retroarch_version, PACKAGE_VERSION, NETPLAY_HOST_STR_LEN); strlcpy(ad_packet_buffer.content, !string_is_empty( path_basename(path_get(RARCH_PATH_BASENAME))) ? path_basename(path_get(RARCH_PATH_BASENAME)) : "N/A", NETPLAY_HOST_LONGSTR_LEN); strlcpy(ad_packet_buffer.nick, netplay->nick, NETPLAY_HOST_STR_LEN); if (info) { strlcpy(ad_packet_buffer.core, info->info.library_name, NETPLAY_HOST_STR_LEN); strlcpy(ad_packet_buffer.core_version, info->info.library_version, NETPLAY_HOST_STR_LEN); } snprintf(s, sizeof(s), "%d", content_crc); strlcpy(ad_packet_buffer.content_crc, s, NETPLAY_HOST_STR_LEN); /* And send it */ sendto(lan_ad_server_fd, (const char*)&ad_packet_buffer, sizeof(struct ad_packet), 0, &their_addr, addr_size); } } return true; }
/** * netplay_net_pre_frame: * @netplay : pointer to netplay object * * Pre-frame for Netplay (normal version). **/ static bool netplay_net_pre_frame(netplay_t *netplay) { retro_ctx_serialize_info_t serial_info; if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->self_ptr], netplay->self_frame_count)) { serial_info.data_const = NULL; serial_info.data = netplay->buffer[netplay->self_ptr].state; serial_info.size = netplay->state_size; memset(serial_info.data, 0, serial_info.size); if ((netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) || netplay->self_frame_count == 0) { /* Don't serialize until it's safe */ } else if (!(netplay->quirks & NETPLAY_QUIRK_NO_SAVESTATES) && core_serialize(&serial_info)) { if (netplay->force_send_savestate && !netplay->stall) { /* Send this along to the other side */ serial_info.data_const = netplay->buffer[netplay->self_ptr].state; netplay_load_savestate(netplay, &serial_info, false); netplay->force_send_savestate = false; } } else { /* If the core can't serialize properly, we must stall for the * remote input on EVERY frame, because we can't recover */ netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; netplay->stall_frames = 0; } /* If we can't transmit savestates, we must stall until the client is ready */ if (!netplay->has_connection && netplay->self_frame_count > 0 && (netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION))) netplay->stall = RARCH_NETPLAY_STALL_NO_CONNECTION; } if (netplay->is_server && !netplay->has_connection) { fd_set fds; struct timeval tmp_tv = {0}; int new_fd; struct sockaddr_storage their_addr; socklen_t addr_size; /* Check for a connection */ FD_ZERO(&fds); FD_SET(netplay->fd, &fds); if (socket_select(netplay->fd + 1, &fds, NULL, NULL, &tmp_tv) > 0 && FD_ISSET(netplay->fd, &fds)) { addr_size = sizeof(their_addr); new_fd = accept(netplay->fd, (struct sockaddr*)&their_addr, &addr_size); if (new_fd < 0) { RARCH_ERR("%s\n", msg_hash_to_str(MSG_NETPLAY_FAILED)); return true; } socket_close(netplay->fd); netplay->fd = new_fd; #if defined(IPPROTO_TCP) && defined(TCP_NODELAY) { int flag = 1; if (setsockopt(netplay->fd, IPPROTO_TCP, TCP_NODELAY, (void*)&flag, sizeof(int)) < 0) RARCH_WARN("Could not set netplay TCP socket to nodelay. Expect jitter.\n"); } #endif #if defined(F_SETFD) && defined(FD_CLOEXEC) /* Don't let any inherited processes keep open our port */ if (fcntl(netplay->fd, F_SETFD, FD_CLOEXEC) < 0) RARCH_WARN("Cannot set Netplay port to close-on-exec. It may fail to reopen if the client disconnects.\n"); #endif /* Establish the connection */ if (netplay_handshake(netplay)) { netplay->has_connection = true; /* Send them the savestate */ if (!(netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION))) { netplay->force_send_savestate = true; } else { /* Because the first frame isn't serialized, we're actually at * frame 1 */ netplay->self_ptr = NEXT_PTR(netplay->self_ptr); netplay->self_frame_count = 1; } /* And expect the current frame from the other side */ netplay->read_frame_count = netplay->other_frame_count = netplay->self_frame_count; netplay->read_ptr = netplay->other_ptr = netplay->self_ptr; /* Unstall if we were waiting for this */ if (netplay->stall == RARCH_NETPLAY_STALL_NO_CONNECTION) netplay->stall = 0; } else { socket_close(netplay->fd); /* FIXME: Get in a state to accept another client */ } } } netplay->can_poll = true; input_poll_net(); return (netplay->stall != RARCH_NETPLAY_STALL_NO_CONNECTION); }
int socket_wait_readable(struct mySocket *sock, struct timeval *timeout) { return socket_select(sock, timeout, 1, 0); }
/** * netplay_pre_frame_spectate: * @netplay : pointer to netplay object * * Pre-frame for Netplay (spectate mode version). **/ static void netplay_spectate_pre_frame(netplay_t *netplay) { unsigned i; uint32_t *header; int new_fd, idx, bufsize; size_t header_size; struct sockaddr_storage their_addr; socklen_t addr_size; fd_set fds; struct timeval tmp_tv = {0}; if (!np_is_server(netplay)) return; FD_ZERO(&fds); FD_SET(netplay->fd, &fds); if (socket_select(netplay->fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0) return; if (!FD_ISSET(netplay->fd, &fds)) return; addr_size = sizeof(their_addr); new_fd = accept(netplay->fd, (struct sockaddr*)&their_addr, &addr_size); if (new_fd < 0) { RARCH_ERR("Failed to accept incoming spectator.\n"); return; } idx = -1; for (i = 0; i < MAX_SPECTATORS; i++) { if (netplay->spectate.fds[i] == -1) { idx = i; break; } } /* No vacant client streams :( */ if (idx == -1) { socket_close(new_fd); return; } if (!np_get_nickname(netplay, new_fd)) { RARCH_ERR("Failed to get nickname from client.\n"); socket_close(new_fd); return; } if (!np_send_nickname(netplay, new_fd)) { RARCH_ERR("Failed to send nickname to client.\n"); socket_close(new_fd); return; } header = np_bsv_header_generate(&header_size, np_impl_magic()); if (!header) { RARCH_ERR("Failed to generate BSV header.\n"); socket_close(new_fd); return; } bufsize = header_size; setsockopt(new_fd, SOL_SOCKET, SO_SNDBUF, (const char*)&bufsize, sizeof(int)); if (!socket_send_all_blocking(new_fd, header, header_size)) { RARCH_ERR("Failed to send header to client.\n"); socket_close(new_fd); free(header); return; } free(header); netplay->spectate.fds[idx] = new_fd; #ifndef HAVE_SOCKET_LEGACY np_log_connection(&their_addr, idx, netplay->other_nick); #endif }