static void NET_Conn_ParseACK(net_connection_t *conn, net_packet_t *packet) { net_packet_t *reply; if (conn->state == NET_CONN_STATE_CONNECTING) { // We are a client // received a response from the server to our SYN conn->state = NET_CONN_STATE_CONNECTED; // We must send an ACK reply to the server's ACK reply = NET_NewPacket(10); NET_WriteInt16(reply, NET_PACKET_TYPE_ACK); NET_Conn_SendPacket(conn, reply); NET_FreePacket(reply); } if (conn->state == NET_CONN_STATE_WAITING_ACK) { // We are a server // Client is connected conn->state = NET_CONN_STATE_CONNECTED; } }
static void NET_CL_SendResendRequest(int start, int end) { net_packet_t *packet; unsigned int nowtime; int i; //printf("CL: Send resend %i-%i\n", start, end); packet = NET_NewPacket(64); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_RESEND); NET_WriteInt32(packet, start); NET_WriteInt8(packet, end - start + 1); NET_Conn_SendPacket(&client_connection, packet); NET_FreePacket(packet); nowtime = I_GetTimeMS(); // Save the time we sent the resend request for (i=start; i<=end; ++i) { int index; index = i - recvwindow_start; if (index < 0 || index >= BACKUPTICS) continue; recvwindow[index].resend_time = nowtime; } }
static void NET_SV_SendWaitingData(net_client_t *client) { net_waitdata_t wait_data; net_packet_t *packet; net_client_t *controller; int i; NET_SV_AssignPlayers(); controller = NET_SV_Controller(); wait_data.num_players = NET_SV_NumPlayers(); wait_data.num_drones = NET_SV_NumDrones(); wait_data.ready_players = NET_SV_NumReadyPlayers(); wait_data.max_players = NET_SV_MaxPlayers(); wait_data.is_controller = (client == controller); wait_data.consoleplayer = client->player_number; // Send the WAD and dehacked checksums of the controlling client. // If no controller found (?), send the details that the client // is expecting anyway. if (controller == NULL) { controller = client; } memcpy(&wait_data.wad_sha1sum, &controller->wad_sha1sum, sizeof(sha1_digest_t)); memcpy(&wait_data.deh_sha1sum, &controller->deh_sha1sum, sizeof(sha1_digest_t)); wait_data.is_freedoom = controller->is_freedoom; // set name and address of each player: for (i = 0; i < wait_data.num_players; ++i) { M_StringCopy(wait_data.player_names[i], sv_players[i]->name, MAXPLAYERNAME); M_StringCopy(wait_data.player_addrs[i], NET_AddrToString(sv_players[i]->addr), MAXPLAYERNAME); } // Construct packet: packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA); NET_WriteWaitData(packet, &wait_data); // Send packet to client and free NET_Conn_SendPacket(&client->connection, packet); NET_FreePacket(packet); }
static void NET_CL_SendTics(int start, int end) { net_packet_t *packet; int i; if (!net_client_connected) { // Disconnected from server return; } if (start < 0) start = 0; // Build a new packet to send to the server packet = NET_NewPacket(512); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA); // Write the start tic and number of tics. Send only the low byte // of start - it can be inferred by the server. NET_WriteInt8(packet, (gametic / ticdup) & 0xff); NET_WriteInt8(packet, start & 0xff); NET_WriteInt8(packet, end - start + 1); // Add the tics. for (i=start; i<=end; ++i) { net_server_send_t *sendobj; sendobj = &send_queue[i % BACKUPTICS]; NET_WriteInt16(packet, average_latency / FRACUNIT); NET_WriteTiccmdDiff(packet, &sendobj->cmd, lowres_turn); } // Send the packet NET_Conn_SendPacket(&client_connection, packet); // All done! NET_FreePacket(packet); // Acknowledgement has been sent as part of the packet need_to_acknowledge = false; }
static void NET_CL_SendSYN(net_connect_data_t *data) { net_packet_t *packet; packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_SYN); NET_WriteInt32(packet, NET_MAGIC_NUMBER); NET_WriteString(packet, PACKAGE_STRING); NET_WriteConnectData(packet, data); NET_WriteString(packet, net_player_name); NET_Conn_SendPacket(&client_connection, packet); NET_FreePacket(packet); }
static boolean NET_Conn_ReliablePacket(net_connection_t *conn, net_packet_t *packet) { unsigned int seq; net_packet_t *reply; boolean result; // Read the sequence number if (!NET_ReadInt8(packet, &seq)) { return true; } if (seq != (unsigned int)(conn->reliable_recv_seq & 0xff)) { // This is not the next expected packet in the sequence! // // Discard the packet. If we were smart, we would use a proper // sliding window protocol to do this, but I'm lazy. result = true; } else { // Now we can receive the next packet in the sequence. conn->reliable_recv_seq = (conn->reliable_recv_seq + 1) & 0xff; result = false; } // Send an acknowledgement // Note: this is braindead. It would be much more sensible to // include this in the next packet, rather than the overhead of // sending a complete packet just for one byte of information. reply = NET_NewPacket(10); NET_WriteInt16(reply, NET_PACKET_TYPE_RELIABLE_ACK); NET_WriteInt8(reply, conn->reliable_recv_seq & 0xff); NET_Conn_SendPacket(conn, reply); NET_FreePacket(reply); return result; }
static void NET_CL_SendGameDataACK(void) { net_packet_t *packet; packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_ACK); NET_WriteInt8(packet, (gametic / ticdup) & 0xff); NET_Conn_SendPacket(&client_connection, packet); NET_FreePacket(packet); need_to_acknowledge = false; }
static void NET_Conn_ParseDisconnect(net_connection_t *conn, net_packet_t *packet) { net_packet_t *reply; // Other end wants to disconnect // Send a DISCONNECT_ACK reply. reply = NET_NewPacket(10); NET_WriteInt16(reply, NET_PACKET_TYPE_DISCONNECT_ACK); NET_Conn_SendPacket(conn, reply); NET_FreePacket(reply); conn->last_send_time = I_GetTimeMS(); conn->state = NET_CONN_STATE_DISCONNECTED_SLEEP; conn->disconnect_reason = NET_DISCONNECT_REMOTE; }
static void NET_CL_SendSYN(void) { net_packet_t *packet; packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_SYN); NET_WriteInt32(packet, NET_MAGIC_NUMBER); NET_WriteString(packet, PACKAGE_STRING); NET_WriteInt16(packet, gamemode); NET_WriteInt16(packet, gamemission); NET_WriteInt8(packet, lowres_turn); NET_WriteInt8(packet, drone); NET_WriteMD5Sum(packet, net_local_wad_md5sum); NET_WriteMD5Sum(packet, net_local_deh_md5sum); NET_WriteInt8(packet, net_local_is_freedoom); NET_WriteString(packet, net_player_name); NET_Conn_SendPacket(&client_connection, packet); NET_FreePacket(packet); }
static void NET_SV_SendResendRequest(net_client_t *client, int start, int end) { net_packet_t *packet; net_client_recv_t *recvobj; int i; unsigned int nowtime; int index; NET_Log("server: send resend to %s for tics %d-%d", NET_AddrToString(client->addr), start, end); packet = NET_NewPacket(20); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_RESEND); NET_WriteInt32(packet, start); NET_WriteInt8(packet, end - start + 1); NET_Conn_SendPacket(&client->connection, packet); NET_FreePacket(packet); // Store the time we send the resend request nowtime = I_GetTimeMS(); for (i=start; i<=end; ++i) { index = i - recvwindow_start; if (index >= BACKUPTICS) { // Outside the range continue; } recvobj = &recvwindow[index][client->player_number]; recvobj->resend_time = nowtime; } }
static void NET_SV_SendTics(net_client_t *client, unsigned int start, unsigned int end) { net_packet_t *packet; unsigned int i; packet = NET_NewPacket(500); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA); // Send the start tic and number of tics NET_WriteInt8(packet, start & 0xff); NET_WriteInt8(packet, end-start + 1); // Write the tics for (i=start; i<=end; ++i) { net_full_ticcmd_t *cmd; cmd = &client->sendqueue[i % BACKUPTICS]; if (i != cmd->seq) { I_Error("Wanted to send %i, but %i is in its place", i, cmd->seq); } // Add command NET_WriteFullTiccmd(packet, cmd, sv_settings.lowres_turn); } // Send packet NET_Conn_SendPacket(&client->connection, packet); NET_FreePacket(packet); }
static void NET_SV_SendWaitingData(net_client_t *client) { net_packet_t *packet; net_client_t *controller; int num_players; int i; NET_SV_AssignPlayers(); controller = NET_SV_Controller(); num_players = NET_SV_NumPlayers(); // time to send the client another status packet packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA); // include the number of players waiting NET_WriteInt8(packet, num_players); // send the number of drone clients NET_WriteInt8(packet, NET_SV_NumDrones()); // indicate whether the client is the controller NET_WriteInt8(packet, client == controller); // send the player number of this client NET_WriteInt8(packet, client->player_number); // send the addresses of all players for (i=0; i<num_players; ++i) { char *addr; // name NET_WriteString(packet, sv_players[i]->name); // address addr = NET_AddrToString(sv_players[i]->addr); NET_WriteString(packet, addr); } // Send the WAD and dehacked checksums of the controlling client. if (controller != NULL) { NET_WriteMD5Sum(packet, controller->wad_md5sum); NET_WriteMD5Sum(packet, controller->deh_md5sum); NET_WriteInt8(packet, controller->is_freedoom); } else { NET_WriteMD5Sum(packet, client->wad_md5sum); NET_WriteMD5Sum(packet, client->deh_md5sum); NET_WriteInt8(packet, client->is_freedoom); } // send packet to client and free NET_Conn_SendPacket(&client->connection, packet); NET_FreePacket(packet); }
void NET_Conn_Run(net_connection_t *conn) { net_packet_t *packet; unsigned int nowtime; nowtime = I_GetTimeMS(); if (conn->state == NET_CONN_STATE_CONNECTED) { // Check the keepalive counters if (nowtime - conn->keepalive_recv_time > CONNECTION_TIMEOUT_LEN * 1000) { // Haven't received any packets from the other end in a long // time. Assume disconnected. conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_TIMEOUT; } if (nowtime - conn->keepalive_send_time > KEEPALIVE_PERIOD * 1000) { // We have not sent anything in a long time. // Send a keepalive. packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_KEEPALIVE); NET_Conn_SendPacket(conn, packet); NET_FreePacket(packet); } // Check the reliable packet list. Has the first packet in the // list timed out? // // NB. This is braindead, we have a fixed time of one second. if (conn->reliable_packets != NULL && (conn->reliable_packets->last_send_time < 0 || nowtime - conn->reliable_packets->last_send_time > 1000)) { // Packet timed out, time to resend NET_Conn_SendPacket(conn, conn->reliable_packets->packet); conn->reliable_packets->last_send_time = nowtime; } } else if (conn->state == NET_CONN_STATE_WAITING_ACK) { if (conn->last_send_time < 0 || nowtime - conn->last_send_time > 1000) { // it has been a second since the last ACK was sent, and // still no reply. if (conn->num_retries < MAX_RETRIES) { // send another ACK packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_ACK); NET_Conn_SendPacket(conn, packet); NET_FreePacket(packet); conn->last_send_time = nowtime; ++conn->num_retries; } else { // no more retries allowed. conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_TIMEOUT; } } } else if (conn->state == NET_CONN_STATE_DISCONNECTING) { // Waiting for a reply to our DISCONNECT request. if (conn->last_send_time < 0 || nowtime - conn->last_send_time > 1000) { // it has been a second since the last disconnect packet // was sent, and still no reply. if (conn->num_retries < MAX_RETRIES) { // send another disconnect packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_DISCONNECT); NET_Conn_SendPacket(conn, packet); NET_FreePacket(packet); conn->last_send_time = nowtime; ++conn->num_retries; } else { // No more retries allowed. // Force disconnect. conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_LOCAL; } } } else if (conn->state == NET_CONN_STATE_DISCONNECTED_SLEEP) { // We are disconnected, waiting in case we need to send // a DISCONNECT_ACK to the server again. if (nowtime - conn->last_send_time > 5000) { // Idle for 5 seconds, switch state conn->state = NET_CONN_STATE_DISCONNECTED; conn->disconnect_reason = NET_DISCONNECT_REMOTE; } } }