int network_udp_bind(UDPsocket udp, int channel, std::string ipp) { std::string ip; int port; ip = ipp.substr(0, ipp.find(":")); port = std::stoi(ipp.substr(ipp.find(":"))); return network_udp_bind(udp, channel, network_resolve_host(ip, port)); }
/* * BEE::net_session_join() - Attempt to join a session at the given IP address * @ip: the IP address to attempt to connect to * @player_name: the name of the player which will be sent to the host */ int BEE::net_session_join(const std::string& ip, const std::string& player_name) { net->players.clear(); // Clear the previous player map net->udp_recv = network_udp_open(net->id); // Open a UDP listening socket to receive messages from the server if (net->udp_recv == nullptr) { return 1; // Return 1 if the receiving socket failed to open } net->channel = network_udp_bind(&net->udp_send, -1, ip, net->id); // Bind a sending socket to the given server IP address if (net->channel == -1) { network_udp_close(&net->udp_recv); // Close the receiving socket return 2; // Return 2 if the sending socket failed to bind } network_udp_send(net->udp_send, net->channel, 0, 1, 0); // Send a server connection request if (network_packet_realloc(net->udp_data, 8)) { // Attempt to allocate space to receive data network_udp_close(&net->udp_recv); // Close the sockets network_udp_close(&net->udp_send); return 3; // Return 3 if the allocation failed } Uint32 t = get_ticks(); // Get the current time int r = network_udp_recv(net->udp_recv, net->udp_data); // Attempt to receive data while ((r < 1)||(get_ticks() - t < net->timeout)) { // Wait to receive data until we timeout r = network_udp_recv(net->udp_recv, net->udp_data); // Attempt to receive data } if ((r < 1)||(net->udp_data->data[0] != 1)) { // If no data was received or if the data was not a connection response network_udp_close(&net->udp_recv); // Close the sockets network_udp_close(&net->udp_send); messenger_send({"engine", "network"}, BEE_MESSAGE_WARNING, "net_session_join() : Failed to connect to " + ip); return 4; // Return 4 on failed to connect } // Set connection info net->self_id = net->udp_data->data[1]; net->is_connected = true; messenger_send({"engine", "network"}, BEE_MESSAGE_INFO, "net_session_join() : Connected to server with id " + net->udp_data->data[1]); return 0; // Return 0 on success }
/* * BEE::net_session_find() - Query the local network for available sessions */ std::map<std::string,std::string> BEE::net_session_find() { net->servers.clear(); // Clear the previously available servers net->udp_recv = network_udp_open(net->id); // Open a UDP listening socket to receive responses from the servers if (net->udp_recv == nullptr) { messenger_send({"engine", "network"}, BEE_MESSAGE_WARNING, "net_session_find() : UDP listening socket failed to open"); return net->servers; // Return an empty map if the receiving socket failed to open } net->channel = network_udp_bind(&net->udp_send, -1, "255.255.255.255", net->id); // Bind a sending socket to the broadcast IP 255.255.255.255 if (net->channel == -1) { network_udp_close(&net->udp_recv); // Close the receiving socket messenger_send({"engine", "network"}, BEE_MESSAGE_WARNING, "net_session_find() : UDP broadcast socket failed to bind"); return net->servers; // Return an empty map if the sending socket failed to bind } network_udp_send(net->udp_send, net->channel, net->self_id, 3, 0); // Send a server name info request if (network_packet_realloc(net->udp_data, 8)) { // Attempt to allocate space to receive data network_udp_close(&net->udp_recv); // Close the sockets network_udp_close(&net->udp_send); messenger_send({"engine", "network"}, BEE_MESSAGE_WARNING, "net_session_find() : Failed to allocate space to receive data"); return net->servers; // Return an empty map if the allocation failed } Uint32 t = get_ticks(); // Get the current time int r = network_udp_recv(net->udp_recv, net->udp_data); // Attempt to receive data while (get_ticks() - t < net->timeout) { // Continue receiving until we timeout if ((r == 1)&&(net->udp_data->data[2] == 3)) { // If data was received and it is a server name info response std::string name = chra(net->udp_data->data+4); // Get the server name from the data net->servers.insert(std::make_pair(network_get_address(net->udp_data->address.host), name)); // Add the server to the list of available servers } r = network_udp_recv(net->udp_recv, net->udp_data); // Attempt to receive more data } network_udp_close(&net->udp_recv); // Close the receiving socket network_udp_close(&net->udp_send); // Close the sending socket return net->servers; // Return the filled map on success }
/* * BEE::net_handle_events() - Handle network sending and receiving during the event loop */ int BEE::net_handle_events() { if ((!options->is_network_enabled)||(!net->is_initialized)) { return 1; // Return 1 if networking is disabled or if it has not been initialized } if (network_packet_realloc(net->udp_data, 8)) { // Attempt to allocate space to receive data return 2; // Return 2 on failed to allocate } int r = network_udp_recv(net->udp_recv, net->udp_data); // Attempt to receive data over the UDP socket if (r == -1) { return 3; // Return 3 on failure while receiving } if (r == 0) { return 0; // Return 0 when there's no data to receive } if (net->is_host) { // Handle session hosting signals switch (net->udp_data->data[2]) { case 1: { // Connection requested if (net->players.size() < net->max_players) { // If there is still room for clients then allow the current one to connect int id = net->players.size(); // Get an id for the client UDPsocket sock = nullptr; int c = network_udp_bind(&sock, -1, &net->udp_data->address); // Bind a sending socket to the client who is requesting a connection network_udp_send(sock, c, 0, 1, id); // Send the client their id net->players.insert(std::pair<int,UDPsocket>(id, sock)); // Add the client to the list of clients messenger_send({"engine", "network"}, BEE_MESSAGE_INFO, "Client accepted"); } break; } case 2: { // Client disconnected network_udp_close(&net->players[net->udp_data->data[1]]); // Close the sending socket to the client who has disconnected net->players.erase(net->udp_data->data[1]); // Remove them from the list of clients messenger_send({"engine", "network"}, BEE_MESSAGE_INFO, "Client disconnected"); break; } case 3: { // Server info request switch (net->udp_data->data[3]) { case 1: { // Client requesting server name Uint8* n = orda(net->name); // Convert the server name to Uint8's Uint8* data = (Uint8*)malloc(4+net->name.length()); // Allocate space for the signals and server name // See Network Message Format at the top of this file for details data[0] = 4+net->name.length(); // Total message length data[1] = 0; // Server id data[2] = 3; // Info request signal data[3] = 1; // Info type signal memcpy(data+4, n, net->name.length()); // Add the server name to the rest of the data network_udp_send(net->players[net->udp_data->data[1]], -1, data); // Send the entire message free(data); // Free the allocated space free(n); break; } case 2: { // Client requesting player map // Convert our player socket map into a map of player IP addresses std::map <int,std::string> t; for (auto& p : net->players) { // Iterate over the connected players and insert their id and IP address into the new map IPaddress* ipa = network_get_peer_address(p.second, -1); if (ipa != nullptr) { t.insert(std::pair<int,std::string>(p.first, network_get_address(ipa->host))); } } Uint8* m = network_map_encode(t); // Encode the player map as a series of Uint8's Uint8* data = (Uint8*)malloc(4+m[0]); // Allocate space for the signals and the map data // See Network Message Format at the top of this file for details data[0] = 4+m[0]; // Total message length data[1] = 0; // Server id data[2] = 3; // Info request signal data[3] = 2; // Info type signal memcpy(data+4, m, m[0]); // Add the map to the rest of the data network_udp_send(net->players[net->udp_data->data[1]], -1, data); // Send the entire message free(data); // Free the allocated space free(m); break; } case 3: { // Client requesting data map Uint8* m = network_map_encode(net->data); // Encode the data map as a series of Uint8's Uint8* data = (Uint8*)malloc(4+m[0]); // Allocate space for the signals and the map data // See Network Message Format at the top of this file for details data[0] = 4+m[0]; // Total message length data[1] = 0; // Server id data[2] = 3; // Info request signal data[3] = 3; // Info type signal memcpy(data+4, m, m[0]); // Add the map to the rest of the data network_udp_send(net->players[net->udp_data->data[1]], -1, data); // Send the entire message free(data); // Free the allocated space free(m); break; } } break; // Break from signal1: 3 info requested } } } else { // Handle client signals switch (net->udp_data->data[2]) { case 1: { // Connection accepted net->self_id = net->udp_data->data[3]; // Read the id that the server assigned to us net->is_connected = true; // Mark our networking as connected messenger_send({"engine", "network"}, BEE_MESSAGE_INFO, "Connected to server with id " + net->udp_data->data[3]); break; } case 2: { // Disconnected by host net->is_connected = false; // Mark our networking as unconnected network_udp_close(&net->udp_send); // Close our sockets which pointed at the host network_udp_close(&net->udp_recv); break; } case 3: { // Server info received switch (net->udp_data->data[3]) { case 1: { // Received server name (along with IP address) std::string ip = network_get_address(net->udp_data->address.host); // Get the server IP std::string name = chra(net->udp_data->data+4); // Get the server name from the data net->servers.insert(std::make_pair(ip, name)); // Add the server to the list of available servers break; } case 2: { // Received player map std::map <std::string,std::string> t; // Temp map to store IP addresses in net->players.clear(); // Remove all players in order to clean out old connections network_map_decode(net->udp_data->data+4, &t); // Decode the player map from the data into t for (auto& p : t) { // Iterate over the players in the temp map in order to generate sockets for each of them UDPsocket sock = nullptr; network_udp_bind(&sock, -1, p.second); // Bind a socket to the player's IP address net->players.insert(std::pair<int,UDPsocket>(bee_stoi(p.first), sock)); // Insert the player's id and IP address into our copy of the player map } break; } case 3: { // Received data map network_map_decode(net->udp_data->data+4, &net->data); // Decode the data map directly into net->data in order to immediately replace all old data break; } } break; // Break from signal1: 3 info received } } } return 0; // Return 0 on success }
int network_udp_bind(UDPsocket udp, int channel, std::string ip, int port) { return network_udp_bind(udp, channel, network_resolve_host(ip, port)); }
/* * network_udp_bind() - Bind the given socket to the given IP address data using the given channel * ! When the function is called with a string, simply call it after separating the address from the port * @udp: the socket to bind * @channel: the channel to use * @ipp: the string containing the IP in the format "127.0.0.1:80" */ int network_udp_bind(UDPsocket* udp, int channel, const std::string& ipp) { std::string ip; int port; ip = ipp.substr(0, ipp.find(":")); // Set the IP address as the string section before the colon port = bee_stoi(ipp.substr(ipp.find(":"))); // Set the port as the string section after the colon return network_udp_bind(udp, channel, ip, port); }