static bool init_lan_ad_server_socket(netplay_t *netplay, uint16_t port) { struct addrinfo *addr = NULL; int fd = socket_init((void **) &addr, port, NULL, SOCKET_TYPE_DATAGRAM); if (fd < 0) goto error; if (!socket_bind(fd, (void*)addr)) { socket_close(fd); goto error; } lan_ad_server_fd = fd; freeaddrinfo_retro(addr); return true; error: if (addr) freeaddrinfo_retro(addr); RARCH_ERR("Failed to initialize netplay advertisement socket.\n"); return false; }
static bool remote_init_network(rarch_remote_t *handle, uint16_t port, unsigned user) { struct addrinfo hints = {0}; char port_buf[16] = {0}; struct addrinfo *res = NULL; int yes = 1; port = port + user; if (!network_init()) return false; RARCH_LOG("Bringing up remote interface on port %hu.\n", (unsigned short)port); #if defined(_WIN32) || defined(HAVE_SOCKET_LEGACY) hints.ai_family = AF_INET; #else hints.ai_family = AF_UNSPEC; #endif hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port); if (getaddrinfo_retro(NULL, port_buf, &hints, &res) < 0) goto error; handle->net_fd[user] = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (handle->net_fd[user] < 0) goto error; if (!socket_nonblock(handle->net_fd[user])) goto error; setsockopt(handle->net_fd[user], SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(int)); if (bind(handle->net_fd[user], res->ai_addr, res->ai_addrlen) < 0) { RARCH_ERR("Failed to bind socket.\n"); goto error; } freeaddrinfo_retro(res); return true; error: if (res) freeaddrinfo_retro(res); return false; }
static int net_http_new_socket(const char *domain, int port) { int fd; #ifndef _WIN32 #ifndef VITA struct timeval timeout; #endif #endif struct addrinfo hints, *addr = NULL; char portstr[16] = {0}; /* Initialize the network. */ if (!network_init()) return -1; snprintf(portstr, sizeof(portstr), "%i", port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; if (getaddrinfo_retro(domain, portstr, &hints, &addr) < 0) return -1; if (!addr) return -1; fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); #ifndef _WIN32 #ifndef VITA timeout.tv_sec=4; timeout.tv_usec=0; setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof timeout); #endif #endif if (connect(fd, addr->ai_addr, addr->ai_addrlen) != 0) { freeaddrinfo_retro(addr); socket_close(fd); return -1; } freeaddrinfo_retro(addr); if (!socket_nonblock(fd)) { socket_close(fd); return -1; } return fd; }
/** * netplay_free: * @netplay : pointer to netplay object * * Frees netplay handle. **/ void netplay_free(netplay_t *netplay) { unsigned i; if (netplay->fd >= 0) socket_close(netplay->fd); if (netplay->spectate.enabled) { for (i = 0; i < MAX_SPECTATORS; i++) if (netplay->spectate.fds[i] >= 0) socket_close(netplay->spectate.fds[i]); free(netplay->spectate.input); } else { for (i = 0; i < netplay->buffer_size; i++) if (netplay->buffer[i].state) free(netplay->buffer[i].state); free(netplay->buffer); } if (netplay->addr) freeaddrinfo_retro(netplay->addr); free(netplay); }
/** Discovery control */ bool netplay_discovery_driver_ctl(enum rarch_netplay_discovery_ctl_state state, void *data) { char port_str[6]; if (lan_ad_client_fd < 0) return false; switch (state) { case RARCH_NETPLAY_DISCOVERY_CTL_LAN_SEND_QUERY: { struct addrinfo hints = {0}, *addr; int canBroadcast = 1; /* Get the broadcast address (IPv4 only for now) */ snprintf(port_str, 6, "%hu", (unsigned short) RARCH_DEFAULT_PORT); if (getaddrinfo_retro("255.255.255.255", port_str, &hints, &addr) < 0) return false; /* Make it broadcastable */ #if defined(SOL_SOCKET) && defined(SO_BROADCAST) if (setsockopt(lan_ad_client_fd, SOL_SOCKET, SO_BROADCAST, (const char *)&canBroadcast, sizeof(canBroadcast)) < 0) RARCH_WARN("Failed to set netplay discovery port to broadcast.\n"); #endif /* Put together the request */ memcpy((void *) &ad_packet_buffer, "RANQ", 4); ad_packet_buffer.protocol_version = htonl(NETPLAY_PROTOCOL_VERSION); /* And send it off */ if (sendto(lan_ad_client_fd, (const char *) &ad_packet_buffer, 2*sizeof(uint32_t), 0, addr->ai_addr, addr->ai_addrlen) < (ssize_t) (2*sizeof(uint32_t))) RARCH_WARN("Failed to send netplay discovery response.\n"); freeaddrinfo_retro(addr); break; } case RARCH_NETPLAY_DISCOVERY_CTL_LAN_GET_RESPONSES: if (!netplay_lan_ad_client()) return false; *((struct netplay_host_list **) data) = &discovered_hosts; break; case RARCH_NETPLAY_DISCOVERY_CTL_LAN_CLEAR_RESPONSES: discovered_hosts.size = 0; break; default: return false; } return true; }
static bool init_udp_socket(netplay_t *netplay, const char *server, uint16_t port) { char port_buf[16] = {0}; struct addrinfo hints = {0}; memset(&hints, 0, sizeof(hints)); #if defined(_WIN32) || defined(HAVE_SOCKET_LEGACY) hints.ai_family = AF_INET; #else hints.ai_family = AF_UNSPEC; #endif hints.ai_socktype = SOCK_DGRAM; if (!server) hints.ai_flags = AI_PASSIVE; snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port); if (getaddrinfo_retro(server, port_buf, &hints, &netplay->addr) < 0) return false; if (!netplay->addr) return false; netplay->udp_fd = socket(netplay->addr->ai_family, netplay->addr->ai_socktype, netplay->addr->ai_protocol); if (netplay->udp_fd < 0) { RARCH_ERR("Failed to initialize socket.\n"); return false; } if (!server) { /* Not sure if we have to do this for UDP, but hey :) */ int yes = 1; setsockopt(netplay->udp_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(int)); if (bind(netplay->udp_fd, netplay->addr->ai_addr, netplay->addr->ai_addrlen) < 0) { RARCH_ERR("Failed to bind socket.\n"); socket_close(netplay->udp_fd); netplay->udp_fd = -1; } freeaddrinfo_retro(netplay->addr); netplay->addr = NULL; } return true; }
static bool init_tcp_socket(netplay_t *netplay, const char *server, uint16_t port, bool spectate) { char port_buf[16] = {0}; bool ret = false; const struct addrinfo *tmp_info = NULL; struct addrinfo hints, *res = NULL; memset(&hints, 0, sizeof(hints)); #if defined(_WIN32) || defined(HAVE_SOCKET_LEGACY) hints.ai_family = AF_INET; #else hints.ai_family = AF_UNSPEC; #endif hints.ai_socktype = SOCK_STREAM; if (!server) hints.ai_flags = AI_PASSIVE; snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port); if (getaddrinfo_retro(server, port_buf, &hints, &res) < 0) return false; if (!res) return false; /* If "localhost" is used, it is important to check every possible * address for IPv4/IPv6. */ tmp_info = res; while (tmp_info) { int fd; if ((fd = init_tcp_connection(tmp_info, server, netplay->spectate.enabled, (struct sockaddr*)&netplay->other_addr, sizeof(netplay->other_addr))) >= 0) { ret = true; netplay->fd = fd; break; } tmp_info = tmp_info->ai_next; } if (res) freeaddrinfo_retro(res); if (!ret) RARCH_ERR("Failed to set up netplay sockets.\n"); return ret; }
/** * netplay_free * @netplay : pointer to netplay object * * Frees netplay data/ */ void netplay_free(netplay_t *netplay) { size_t i; if (netplay->listen_fd >= 0) socket_close(netplay->listen_fd); for (i = 0; i < netplay->connections_size; i++) { struct netplay_connection *connection = &netplay->connections[i]; if (connection->active) { socket_close(connection->fd); netplay_deinit_socket_buffer(&connection->send_packet_buffer); netplay_deinit_socket_buffer(&connection->recv_packet_buffer); } } if (netplay->connections && netplay->connections != &netplay->one_connection) free(netplay->connections); if (netplay->nat_traversal) natt_free(&netplay->nat_traversal_state); if (netplay->buffer) { for (i = 0; i < netplay->buffer_size; i++) if (netplay->buffer[i].state) free(netplay->buffer[i].state); free(netplay->buffer); } if (netplay->zbuffer) free(netplay->zbuffer); if (netplay->compress_nil.compression_stream) { netplay->compress_nil.compression_backend->stream_free(netplay->compress_nil.compression_stream); netplay->compress_nil.decompression_backend->stream_free(netplay->compress_nil.decompression_stream); } if (netplay->compress_zlib.compression_stream) { netplay->compress_zlib.compression_backend->stream_free(netplay->compress_zlib.compression_stream); netplay->compress_zlib.decompression_backend->stream_free(netplay->compress_zlib.decompression_stream); } if (netplay->addr) freeaddrinfo_retro(netplay->addr); free(netplay); }
bool udp_send_packet(const char *host, uint16_t port, const char *msg) { char port_buf[16] = {0}; struct addrinfo hints = {0}; struct addrinfo *res = NULL; const struct addrinfo *tmp = NULL; int fd = -1; bool ret = true; hints.ai_socktype = SOCK_DGRAM; snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port); if (getaddrinfo_retro(host, port_buf, &hints, &res) != 0) return false; /* Send to all possible targets. * "localhost" might resolve to several different IPs. */ tmp = (const struct addrinfo*)res; while (tmp) { ssize_t len, ret_len; fd = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol); if (fd < 0) { ret = false; goto end; } len = strlen(msg); ret_len = sendto(fd, msg, len, 0, tmp->ai_addr, tmp->ai_addrlen); if (ret_len < len) { ret = false; goto end; } socket_close(fd); fd = -1; tmp = tmp->ai_next; } end: freeaddrinfo_retro(res); if (fd >= 0) socket_close(fd); return ret; }
static bool input_remote_init_network(input_remote_t *handle, uint16_t port, unsigned user) { int fd; struct addrinfo *res = NULL; port = port + user; if (!network_init()) return false; RARCH_LOG("Bringing up remote interface on port %hu.\n", (unsigned short)port); fd = socket_init((void**)&res, port, NULL, SOCKET_TYPE_DATAGRAM); if (fd < 0) goto error; handle->net_fd[user] = fd; if (!socket_nonblock(handle->net_fd[user])) goto error; if (!socket_bind(handle->net_fd[user], res)) { RARCH_ERR("Failed to bind socket.\n"); goto error; } freeaddrinfo_retro(res); return true; error: if (res) freeaddrinfo_retro(res); return false; }
/** Initialize Netplay discovery (client) */ bool init_netplay_discovery(void) { struct addrinfo *addr = NULL; int fd = socket_init((void **) &addr, 0, NULL, SOCKET_TYPE_DATAGRAM); if (fd < 0) goto error; if (!socket_bind(fd, (void*)addr)) { socket_close(fd); goto error; } lan_ad_client_fd = fd; freeaddrinfo_retro(addr); return true; error: if (addr) freeaddrinfo_retro(addr); RARCH_ERR("Failed to initialize netplay advertisement client socket.\n"); return false; }
static int net_http_new_socket(struct http_connection_t *conn) { int ret; struct addrinfo *addr = NULL, *next_addr = NULL; int fd = socket_init( (void**)&addr, conn->port, conn->domain, SOCKET_TYPE_STREAM); #ifdef HAVE_SSL if (conn->sock_state.ssl) { if (!(conn->sock_state.ssl_ctx = ssl_socket_init(fd, conn->domain))) return -1; } #endif next_addr = addr; while(fd >= 0) { #ifdef HAVE_SSL if (conn->sock_state.ssl) { ret = ssl_socket_connect(conn->sock_state.ssl_ctx, (void*)next_addr, true, true); if (ret >= 0) break; ssl_socket_close(conn->sock_state.ssl_ctx); } else #endif { ret = socket_connect(fd, (void*)next_addr, true); if (ret >= 0 && socket_nonblock(fd)) break; socket_close(fd); } fd = socket_next((void**)&next_addr); } if (addr) freeaddrinfo_retro(addr); conn->sock_state.fd = fd; return fd; }
bool natt_open_port_any(struct natt_status *status, uint16_t port, enum socket_protocol proto) { #if !defined(HAVE_SOCKET_LEGACY) && !defined(WIIU) size_t i; char port_str[6]; struct net_ifinfo list; struct addrinfo hints = {0}, *addr; bool ret = false; snprintf(port_str, sizeof(port_str), "%hu", port); /* get our interfaces */ if (!net_ifinfo_new(&list)) return false; /* loop through them */ for (i = 0; i < list.size; i++) { struct net_ifinfo_entry *entry = list.entries + i; /* ignore localhost */ if ( string_is_equal(entry->host, "127.0.0.1") || string_is_equal(entry->host, "::1")) continue; /* make a request for this host */ if (getaddrinfo_retro(entry->host, port_str, &hints, &addr) == 0) { ret = natt_open_port(status, addr->ai_addr, addr->ai_addrlen, proto) || ret; freeaddrinfo_retro(addr); } } net_ifinfo_free(&list); return ret; #else return false; #endif }
static int net_http_new_socket(const char *domain, int port) { int ret; struct addrinfo *addr = NULL; int fd = socket_init((void**)&addr, port, domain, SOCKET_TYPE_STREAM); if (fd < 0) return -1; ret = socket_connect(fd, (void*)addr, true); freeaddrinfo_retro(addr); if (ret < 0) goto error; if (!socket_nonblock(fd)) goto error; return fd; error: socket_close(fd); return -1; }
static bool natt_open_port(struct natt_status *status, struct sockaddr *addr, socklen_t addrlen, enum socket_protocol proto) { #ifndef HAVE_SOCKET_LEGACY #if HAVE_MINIUPNPC int r; char host[PATH_MAX_LENGTH], ext_host[PATH_MAX_LENGTH], port_str[6], ext_port_str[6]; struct addrinfo hints = {0}; const char *proto_str = NULL; struct addrinfo *ext_addrinfo = NULL; /* if NAT traversal is uninitialized or unavailable, oh well */ if (!urls.controlURL || !urls.controlURL[0]) return false; /* figure out the internal info */ if (getnameinfo(addr, addrlen, host, PATH_MAX_LENGTH, port_str, 6, NI_NUMERICHOST|NI_NUMERICSERV) != 0) return false; proto_str = (proto == SOCKET_PROTOCOL_UDP) ? "UDP" : "TCP"; /* add the port mapping */ r = UPNP_AddAnyPortMapping(urls.controlURL, data.first.servicetype, port_str, port_str, host, "retroarch", proto_str, NULL, "3600", ext_port_str); if (r != 0) { /* try the older AddPortMapping */ memcpy(ext_port_str, port_str, 6); r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port_str, port_str, host, "retroarch", proto_str, NULL, "3600"); } if (r != 0) return false; /* get the external IP */ r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, ext_host); if (r != 0) return false; /* update the status */ if (getaddrinfo_retro(ext_host, ext_port_str, &hints, &ext_addrinfo) != 0) return false; if (ext_addrinfo->ai_family == AF_INET && ext_addrinfo->ai_addrlen >= sizeof(struct sockaddr_in)) { status->have_inet4 = true; status->ext_inet4_addr = *((struct sockaddr_in *) ext_addrinfo->ai_addr); } #if defined(AF_INET6) && !defined(HAVE_SOCKET_LEGACY) else if (ext_addrinfo->ai_family == AF_INET6 && ext_addrinfo->ai_addrlen >= sizeof(struct sockaddr_in6)) { status->have_inet6 = true; status->ext_inet6_addr = *((struct sockaddr_in6 *) ext_addrinfo->ai_addr); } #endif else { freeaddrinfo_retro(ext_addrinfo); return false; } freeaddrinfo_retro(ext_addrinfo); return true; #else return false; #endif #else return false; #endif }
static bool init_tcp_socket(netplay_t *netplay, void *direct_host, const char *server, uint16_t port) { char port_buf[16]; bool ret = false; const struct addrinfo *tmp_info = NULL; struct addrinfo *res = NULL; struct addrinfo hints = {0}; port_buf[0] = '\0'; if (!direct_host) { #ifdef HAVE_INET6 /* Default to hosting on IPv6 and IPv4 */ if (!server) hints.ai_family = AF_INET6; #endif hints.ai_socktype = SOCK_STREAM; if (!server) hints.ai_flags = AI_PASSIVE; snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port); if (getaddrinfo_retro(server, port_buf, &hints, &res) < 0) { #ifdef HAVE_INET6 if (!server) { /* Didn't work with IPv6, try wildcard */ hints.ai_family = 0; if (getaddrinfo_retro(server, port_buf, &hints, &res) < 0) return false; } else #endif return false; } if (!res) return false; } else { /* I'll build my own addrinfo! With blackjack and hookers! */ struct netplay_host *host = (struct netplay_host *) direct_host; hints.ai_family = host->addr.sa_family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_addrlen = host->addrlen; hints.ai_addr = &host->addr; res = &hints; } /* If we're serving on IPv6, make sure we accept all connections, including * IPv4 */ #ifdef HAVE_INET6 if (!direct_host && !server && res->ai_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) res->ai_addr; sin6->sin6_addr = in6addr_any; } #endif /* If "localhost" is used, it is important to check every possible * address for IPv4/IPv6. */ tmp_info = res; while (tmp_info) { struct sockaddr_storage sad; int fd = init_tcp_connection( tmp_info, direct_host || server, (struct sockaddr*)&sad, sizeof(sad)); if (fd >= 0) { ret = true; if (direct_host || server) { netplay->connections[0].active = true; netplay->connections[0].fd = fd; netplay->connections[0].addr = sad; } else { netplay->listen_fd = fd; } break; } tmp_info = tmp_info->ai_next; } if (res && !direct_host) freeaddrinfo_retro(res); if (!ret) RARCH_ERR("Failed to set up netplay sockets.\n"); return ret; }