static void ackClient(IPaddress clientAddr) { IPXHeader regHeader; UDPpacket regPacket; Bits result; SDLNet_Write16(0xffff, regHeader.checkSum); SDLNet_Write16(sizeof(regHeader), regHeader.length); SDLNet_Write32(0, regHeader.dest.network); PackIP(clientAddr, ®Header.dest.addr.byIP); SDLNet_Write16(0x2, regHeader.dest.socket); SDLNet_Write32(1, regHeader.src.network); PackIP(ipxServerIp, ®Header.src.addr.byIP); SDLNet_Write16(0x2, regHeader.src.socket); regHeader.transControl = 0; regPacket.data = (Uint8 *)®Header; regPacket.len = sizeof(regHeader); regPacket.maxlen = sizeof(regHeader); regPacket.address = clientAddr; // Send registration string to client. If client doesn't get this, client will not be registered result = SDLNet_UDP_Send(ipxServerSocket,-1,®Packet); }
static bool TryRecvSynAndSendSynAck(NetInput *n) { // listen for SYN if (!NetInputRecvNonBlocking(&n->channel, TryParseSyn, &n->channel)) { return false; } // Send SYN-ACK bool res = false; UDPpacket packet = NetInputNewPacket(&n->channel, sizeof(NetMsgSynAck)); NetMsgSynAck *packetSyn = (NetMsgSynAck *)packet.data; n->channel.seq = rand() & (Uint16)-1; SDLNet_Write16(n->channel.seq, &packetSyn->seq); SDLNet_Write16(n->channel.ack, &packetSyn->ack); if (!NetInputTrySendPacket(&n->channel, packet)) { goto bail; } n->channel.seq++; res = true; bail: CFREE(packet.data); return res; }
void ClientConnection::send_scroll() { int x = get_x(); int y = get_y(); int dx = World::difference(x, old_x); int dy = World::difference(y, old_y); old_x = x; old_y = y; for (typeof(client_entities.begin()) it = client_entities.begin(); it != client_entities.end(); ++it) { it->second.x -= dx; it->second.y -= dy; } static const int len = 5; DataPacket packet = { len, new char[len] }; packet.data[0] = 'S'; SDLNet_Write16(dx, packet.data + 1); SDLNet_Write16(dy, packet.data + 3); SDL_LockMutex(send_mutex); data_to_send.push_back(packet); SDL_UnlockMutex(send_mutex); }
void actWallBuilder(Entity *my) { int c; if( !my->skill[28] ) return; // received on signal if( my->skill[28] == 2) { playSoundEntity( my, 182, 64 ); Uint16 x = std::min<Uint16>(std::max(0.0,my->x/16),map.width-1); Uint16 y = std::min<Uint16>(std::max(0.0,my->y/16),map.height-1); map.tiles[OBSTACLELAYER+y*MAPLAYERS+x*MAPLAYERS*map.height] = map.tiles[y*MAPLAYERS+x*MAPLAYERS*map.height]; if( multiplayer==SERVER ) { for( c=0; c<MAXPLAYERS; c++ ) { if( client_disconnected[c]==TRUE ) continue; strcpy((char *)net_packet->data,"WALC"); SDLNet_Write16(x,&net_packet->data[4]); SDLNet_Write16(y,&net_packet->data[6]); net_packet->address.host = net_clients[c-1].host; net_packet->address.port = net_clients[c-1].port; net_packet->len = 8; sendPacketSafe(net_sock, -1, net_packet, c-1); } } list_RemoveNode(my->mynode); } }
bool Replay::StartRecording(const std::string& game_mode_name, const std::string& game_mode, const std::string& game_mode_objects) { MSG_DEBUG("replay", "Asked to start recording\n"); ASSERT(is_recorder && replay_state == PAUSED_RECORD); replay_state = RECORDING; start_time = 0; old_time = 0; // Write game mode rules at start of data uint total_size = game_mode_name.size() + game_mode.size() + game_mode_objects.size() + 3*2; ChangeBufsize(total_size+30000); // twice the needed size Uint16 size = game_mode_name.size(); SDLNet_Write16(size, ptr); ptr += 2; memcpy(ptr, game_mode_name.c_str(), size); ptr += size; size = game_mode.size(); SDLNet_Write16(size, ptr); ptr += 2; memcpy(ptr, game_mode.c_str(), size); ptr += size; size = game_mode_objects.size(); SDLNet_Write16(size, ptr); ptr += 2; memcpy(ptr, game_mode_objects.c_str(), size); ptr += size; MSG_DEBUG("replay", "Wrote game mode on %u bytes\n", total_size); count = 0; return true; }
// send acknowledgement packet int network_acknowledge( Uint16 sync ) { SDLNet_Write16(PACKET_ACKNOWLEDGE, &packet_out_temp->data[0]); SDLNet_Write16(sync, &packet_out_temp->data[2]); network_send_no_ack(4); return 0; }
// prepare new packet for sending void network_prepare( Uint16 type ) { #ifdef __BLACKBERRY__ #else SDLNet_Write16(type, &packet_out_temp->data[0]); SDLNet_Write16(last_out_sync, &packet_out_temp->data[2]); #endif }
bool PacketManager::Send(TCPsocket socket, Uint16 packetID){ if(socket == NULL)return false; if((buffer == NULL)||(bufferSize < 4))if(!Allocate(4))return false; if(bufferSize < dataLength)return false; Uint16 len = dataLength - 4; SDLNet_Write16(packetID, buffer); SDLNet_Write16(len, buffer + sizeof(Uint16)); lastPackID = packetID; return ((Uint32)SDLNet_TCP_Send(socket, buffer, dataLength) == dataLength); }
// prepare new state for sending void network_state_prepare( void ) { if (packet_state_out[0]) { fprintf(stderr, "warning: state packet overwritten (previous packet remains unsent)\n"); } else { packet_state_out[0] = SDLNet_AllocPacket(NET_PACKET_SIZE); packet_state_out[0]->len = 28; } SDLNet_Write16(PACKET_STATE, &packet_state_out[0]->data[0]); SDLNet_Write16(last_state_out_sync, &packet_state_out[0]->data[2]); memset(&packet_state_out[0]->data[4], 0, 28 - 4); }
void NetInputClientConnect(NetInputClient *n, Uint32 host) { if (!NetInputChannelTryOpen(&n->channel, 0, host)) { printf("Failed to open channel\n"); return; } n->channel.otherPort = NET_INPUT_UDP_PORT; // Handshake // Send SYN UDPpacket packet = NetInputNewPacket(&n->channel, sizeof(NetMsgSyn)); NetMsgSyn *packetSyn = (NetMsgSyn *)packet.data; n->channel.seq = rand() & (Uint16)-1; SDLNet_Write16(n->channel.seq, &packetSyn->seq); if (!NetInputTrySendPacket(&n->channel, packet)) { printf("Failed to send SYN\n"); goto bail; } n->channel.seq++; // Wait for SYN-ACK // TODO: don't wait forever n->channel.state = CHANNEL_STATE_WAIT_HANDSHAKE; while (!NetInputRecvBlocking(&n->channel, TryParseSynAck, &n->channel)) { // Spin } // Send ACK CFREE(packet.data); packet = NetInputNewPacket(&n->channel, sizeof(NetMsgAck)); NetMsgAck *packetAck = (NetMsgAck *)packet.data; SDLNet_Write16(n->channel.ack, &packetAck->ack); if (!NetInputTrySendPacket(&n->channel, packet)) { printf("Failed to send ACK\n"); goto bail; } n->channel.state = CHANNEL_STATE_CONNECTED; return; bail: CFREE(packet.data); }
/* Sends messages to remove old entities which were not sent since last call */ void ClientConnection::send_entity_removals() { std::vector<Uint32> old_entities; for (typeof(client_entities.begin()) it = client_entities.begin(); it != client_entities.end(); ++it) { if (it->second.old) { // This entity is old and should be removed old_entities.push_back(it->first); static const int len = 3; DataPacket packet = { len, new char[len] }; packet.data[0] = 'r'; SDLNet_Write16(it->second.id, packet.data + 1); SDL_LockMutex(send_mutex); data_to_send.push_back(packet); SDL_UnlockMutex(send_mutex); continue; } else { // Next time this will be old if it hasn't been seen again it->second.old = true; } } // Forget the old entities for (typeof(old_entities.begin()) it = old_entities.begin(); it != old_entities.end(); ++it) client_entities.erase(*it); }
// send state packet, xor packet if applicable int network_state_send( void ) { #ifdef __BLACKBERRY__ #else if (!SDLNet_UDP_Send(socket, 0, packet_state_out[0])) { printf("SDLNet_UDP_Send: %s\n", SDL_GetError()); return -1; } // send xor of last network_delay packets if (network_delay > 1 && (last_state_out_sync + 1) % network_delay == 0 && packet_state_out[network_delay - 1] != NULL) { packet_copy(packet_temp, packet_state_out[0]); SDLNet_Write16(PACKET_STATE_XOR, &packet_temp->data[0]); for (int i = 1; i < network_delay; i++) for (int j = 4; j < packet_temp->len; j++) packet_temp->data[j] ^= packet_state_out[i]->data[j]; if (!SDLNet_UDP_Send(socket, 0, packet_temp)) { printf("SDLNet_UDP_Send: %s\n", SDL_GetError()); return -1; } } packets_shift_down(packet_state_out, NET_PACKET_QUEUE); last_state_out_sync++; #endif return 0; }
bool PacketManager::Write16(Uint16 val){ Uint32 size = dataPos + sizeof(Uint16); if(bufferSize < size)if(!Allocate(size))return false; SDLNet_Write16(val, buffer + dataPos); dataPos += sizeof(Uint16); if(dataLength < dataPos)dataLength = dataPos; return true; }
/* Sends an entity with coordinates relative to our entity */ void ClientConnection::send_hud() { std::vector<Entity::HudIcon> icons = entity->get_hud_icons(); int i = 0; for (typeof(icons.begin()) it = icons.begin(); it != icons.end(); ++it) { static const int len = 15; DataPacket packet = { len, new char[len] }; packet.data[0] = 'h'; SDLNet_Write16(i++, packet.data + 1); // id SDLNet_Write16(it->x, packet.data + 3); // x SDLNet_Write16(it->y, packet.data + 5); // y SDLNet_Write16(0, packet.data + 7); // z SDLNet_Write16(it->width, packet.data + 9); // width SDLNet_Write16(it->height, packet.data + 11); // height SDLNet_Write16(it->tex, packet.data + 13); // texture SDL_LockMutex(send_mutex); data_to_send.push_back(packet); SDL_UnlockMutex(send_mutex); } }
UDPpacket NetInputNewPacket(NetInputChannel *n, size_t len) { UDPpacket packet; SDLNet_Write32(n->otherHost, &packet.address.host); SDLNet_Write16(n->otherPort, &packet.address.port); packet.maxlen = packet.len = len; CMALLOC(packet.data, len); return packet; }
void splitForSend(const INFPacket& src, PacketList& destList){ //clear out queue destList.clear(); //segments std::vector<Uint8> tmp; tmp.reserve(maxSendSize); size_t dataIndex = 0; Uint16 len = 0; Uint8 len_buff[2]; unsigned int remaining = 0; while( dataIndex < src.data.size() ){ // Packet header if( dataIndex == 0 ){ tmp.push_back(ControlByte::START.getVal() ); } else { tmp.push_back(ControlByte::CONTINUE.getVal() ); } // data //minus 2 from maxSendSize for the START/END //minus 2 again, becuase 2 bytes are used to store the length // of this segment //how much of the input data is left to be packed remaining = src.data.size() - dataIndex; //the length of the next segment if( remaining > (maxSendSize-4) ){ len = (maxSendSize-4); } else { len = remaining; } //insert the length of this segment SDLNet_Write16(len, len_buff); tmp.push_back( len_buff[0] ); tmp.push_back( len_buff[1] ); //write the actual data for(int i = 0; i < len; ++i){ tmp.push_back( src.data[dataIndex] ); ++dataIndex; } // Packet footer if( dataIndex == src.getLength() ){ tmp.push_back(ControlByte::END.getVal() ); } else { tmp.push_back(ControlByte::WAIT_MORE.getVal() ); } // Put the packet on the list destList.push_back(tmp); tmp.clear(); } }
void Framework::sendPacket(Peer* receiver, char* data, int size) { unsigned short shorty; // we need the port number in network byte order, otherwise it would be the wrong port SDLNet_Write16(sendport, &shorty); IPaddress ip = { receiver->host, shorty }; NET2_UDPSend(&ip, data, size); }
void sendshort(TCPsocket sock, Uint16 i) { Uint16 cmd; int bytes_sent; SDLNet_Write16(i, &cmd); if ((bytes_sent = SDLNet_TCP_Send(sock, &cmd, sizeof(cmd))) != sizeof(cmd)) { fprintf(stderr, "SDLNet_TCP_Send: %s\n", SDLNet_GetError()); } }
// The Replay packet header: // u32: time (ms => 2^16=65s => u16 sufficient) // Packet is directly an action: // . u32 => type // . u32 => length // . data void Replay::StoreAction(const Action* a) { uint size; ASSERT(is_recorder && replay_state==RECORDING); Action::Action_t type = a->GetType(); if ((type!=Action::ACTION_CHAT_INGAME_MESSAGE && a->IsFrameLess()) || type == Action::ACTION_NETWORK_PING || type == Action::ACTION_NETWORK_VERIFY_RANDOM_SYNC || type == Action::ACTION_TIME_VERIFY_SYNC || type == Action::ACTION_RULES_SET_GAME_MODE) return; // Special case to convert into local packet if (type == Action::ACTION_REQUEST_BONUS_BOX_DROP) { // The timestamp shouldn't have moved Action a(Action::ACTION_DROP_BONUS_BOX); StoreAction(&a); return; } size = a->GetSize(); // Enlarge buffer if it can't contain max packet size if (MemUsed() > bufsize - size + 2) ChangeBufsize(bufsize+30000); if (type != Action::ACTION_GAME_CALCULATE_FRAME) { if (count) { count--; MSG_DEBUG("replay", "Calculate frame repeated %u\n", count); // 16 bits is sufficient, around 22 minutes without other actions SDLNet_Write16(count, ptr); ptr += 2; } MSG_DEBUG("replay", "Storing action %s: type=%i length=%i\n", ActionHandler::GetActionName(type).c_str(), type, size); a->Write((char*)ptr); ptr += size; count = 0; } else { if (!count) { // Packet body a->Write((char*)ptr); ptr += size; } count++; } // Check time if (start_time == 0) start_time = GameTime::GetInstance()->Read(); else old_time = GameTime::GetInstance()->Read(); }
unsigned short host_to_net16(unsigned int value) { union { unsigned short s; char b[2]; } data; SDLNet_Write16(value, data.b); return data.s; }
TCP_Listener::TCP_Listener(const Uint16 &port) : sock(0) { get_Net(); IPaddress ip = {0, 0}; SDLNet_Write16(port, &ip.port); sock = SDLNet_TCP_Open(&ip); if(!sock) throw TCP_Socket_Init_Failure(); }
bool PacketManager::WriteChunk(const Uint8 *chunk, Uint16 length){ if(chunk == NULL)length = 0; Uint32 size = dataPos + length + sizeof(Uint16); if(bufferSize < size)if(!Allocate(size))return false; SDLNet_Write16(length, buffer + dataPos); dataPos += sizeof(Uint16); for(size_t n = 0; n<length; n++){ buffer[dataPos] = chunk[n]; dataPos++; } if(dataLength < dataPos)dataLength = dataPos; return true; }
void Client::send(Uint16 number) { char data[2]; const int len = sizeof(data); SDLNet_Write16(number, (Uint16 *)data); // to network byte order int result = SDLNet_TCP_Send(sock, data, len); if (result < len) { printf("%s:%d SDLNet_TCP_Send: %s\n", __FILE__, __LINE__, SDLNet_GetError()); // It may be good to disconnect sock because it is likely invalid now. } }
TCP_NetServer::TCP_NetServer(ushort port) : TCP_NetBase(), remoteMutex(SDL_CreateMutex()) { memset(&remote, 0, sizeof(remote)); IPaddress addr; addr.host = INADDR_ANY; SDLNet_Write16(port, &addr.port); mySocket = SDLNet_TCP_Open(&addr); if (mySocket == NULL) { NETMSG("Failed to initialize TCP server socket"); setErrorFlag(); return; } }
void Action::Push(const std::string& m_val) { // First, write the size of the string (assume len<65536): uint16_t size = m_val.size(); if (MemWriteLeft() < uint(size+2)) Increase(size+2); SDLNet_Write16(size, m_write); m_write += 2; // Then write the actual string if (size) { memcpy(m_write, m_val.c_str(), size); m_write += size; } m_header.len += size+2; }
void BomberNetClient::sendKeystate() { char data[38]; memset(data, 0, sizeof data); SDLNet_Write32(requestNumber, data); data[4] = 0x02; data[5] = GameConfig::Instance().getNbPlayerOfClient(); int pos = 6; for (int i = 0; i < GameConfig::Instance().getNbPlayerOfClient(); i++) { SDLNet_Write16(keystate[i], data + pos); pos += 2; } data[pos] = '\0'; if (SDLNet_CheckSockets(BomberNetClient::socketset, 0) >= 0) { SDLNet_TCP_Send(BomberNetClient::tcpsock, &data, pos); requestNumber++; } }
// attempt to punch through firewall by firing off UDP packets at the opponent // exchange game information int network_connect( void ) { #ifdef __BLACKBERRY__ #else SDLNet_ResolveHost(&ip, network_opponent_host, network_opponent_port); SDLNet_UDP_Bind(socket, 0, &ip); Uint16 episodes = 0, episodes_local = 0; assert(EPISODE_MAX <= 16); for (int i = EPISODE_MAX - 1; i >= 0; i--) { episodes <<= 1; episodes |= (episodeAvail[i] != 0); } episodes_local = episodes; assert(NET_PACKET_SIZE - 12 >= 20 + 1); if (strlen(network_player_name) > 20) network_player_name[20] = '\0'; connect_reset: network_prepare(PACKET_CONNECT); SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]); SDLNet_Write16(network_delay, &packet_out_temp->data[6]); SDLNet_Write16(episodes_local, &packet_out_temp->data[8]); SDLNet_Write16(thisPlayerNum, &packet_out_temp->data[10]); strcpy((char *)&packet_out_temp->data[12], network_player_name); network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT // until opponent sends connect packet while (true) { push_joysticks_as_keyboard(); service_SDL_events(false); if (newkey && lastkey_sym == SDLK_ESCAPE) network_tyrian_halt(0, false); // never timeout last_in_tick = SDL_GetTicks(); if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT) break; network_update(); network_check(); SDL_Delay(16); } connect_again: if (SDLNet_Read16(&packet_in[0]->data[4]) != NET_VERSION) { fprintf(stderr, "error: network version did not match opponent's\n"); network_tyrian_halt(4, true); } if (SDLNet_Read16(&packet_in[0]->data[6]) != network_delay) { fprintf(stderr, "error: network delay did not match opponent's\n"); network_tyrian_halt(5, true); } if (SDLNet_Read16(&packet_in[0]->data[10]) == thisPlayerNum) { fprintf(stderr, "error: player number conflicts with opponent's\n"); network_tyrian_halt(6, true); } episodes = SDLNet_Read16(&packet_in[0]->data[8]); for (int i = 0; i < EPISODE_MAX; i++) { episodeAvail[i] &= (episodes & 1); episodes >>= 1; } network_opponent_name = malloc(packet_in[0]->len - 12 + 1); strcpy(network_opponent_name, (char *)&packet_in[0]->data[12]); network_update(); // until opponent has acknowledged while (!network_is_sync()) { service_SDL_events(false); // got a duplicate packet; process it again (but why?) if (packet_in[0] && SDLNet_Read16(&packet_in[0]->data[0]) == PACKET_CONNECT) goto connect_again; network_check(); // maybe opponent didn't get our packet if (SDL_GetTicks() - last_out_tick > NET_RETRY) goto connect_reset; SDL_Delay(16); } // send another packet since sometimes the network syncs without both connect packets exchanged // there should be a better way to handle this network_prepare(PACKET_CONNECT); SDLNet_Write16(NET_VERSION, &packet_out_temp->data[4]); SDLNet_Write16(network_delay, &packet_out_temp->data[6]); SDLNet_Write16(episodes_local, &packet_out_temp->data[8]); SDLNet_Write16(thisPlayerNum, &packet_out_temp->data[10]); strcpy((char *)&packet_out_temp->data[12], network_player_name); network_send(12 + strlen(network_player_name) + 1); // PACKET_CONNECT connected = true; #endif return 0; }
void ClientConnection::send_entity(Uint32 eid, const Entity *ent) { DataEntity dent = { eid, ent->world->difference(ent->get_x(), get_x()) * 64 + ent->get_offset_x(), ent->world->difference(ent->get_y(), get_y()) * 64 + ent->get_offset_y(), ent->get_z() + ent->get_offset_z(), ent->get_w(), ent->get_h(), ent->get_tex(), false }; // Check if the entity exists allready typeof(client_entities.begin()) it = client_entities.find(eid); if (it != client_entities.end()) { DataEntity &itde = it->second; // Check bounds if ((dent.x + dent.w < -1024 || dent.x > 1024 || dent.y + dent.h < -1024 || dent.y > 1024) && (itde.x + itde.w < -1024 || itde.x > 1024 || itde.y + itde.h < -1024 || itde.y > 1024)) return; // FIXME: If the entity moves across a corner, it will never be sent // If it exists send only modifications bool move = itde.x != dent.x || itde.y != dent.y || itde.z != dent.z; bool resize = itde.w != dent.w || itde.h != dent.h; bool change_tex = itde.tex != dent.tex; itde = dent; if (!move && !resize && !change_tex) return; // Nothing has changed, send nothing if (move && !resize && !change_tex) { // Only move the entity static const int len = 9; DataPacket packet = { len, new char[len] }; packet.data[0] = 'M'; SDLNet_Write16(dent.id, packet.data + 1); SDLNet_Write16(dent.x, packet.data + 3); SDLNet_Write16(dent.y, packet.data + 5); SDLNet_Write16(dent.z, packet.data + 7); SDL_LockMutex(send_mutex); data_to_send.push_back(packet); SDL_UnlockMutex(send_mutex); return; } if (!move && (resize || change_tex)) { // Only send width height and texture static const int len = 9; DataPacket packet = { len, new char[len] }; packet.data[0] = 'i'; SDLNet_Write16(dent.id, packet.data + 1); SDLNet_Write16(dent.w, packet.data + 3); SDLNet_Write16(dent.h, packet.data + 5); SDLNet_Write16(dent.tex, packet.data + 7); SDL_LockMutex(send_mutex); data_to_send.push_back(packet); SDL_UnlockMutex(send_mutex); return; } { // Otherwise send everything static const int len = 15; DataPacket packet = { len, new char[len] }; packet.data[0] = 'a'; SDLNet_Write16(dent.id, packet.data + 1); SDLNet_Write16(dent.x, packet.data + 3); SDLNet_Write16(dent.y, packet.data + 5); SDLNet_Write16(dent.z, packet.data + 7); SDLNet_Write16(dent.w, packet.data + 9); SDLNet_Write16(dent.h, packet.data + 11); SDLNet_Write16(dent.tex, packet.data + 13); SDL_LockMutex(send_mutex); data_to_send.push_back(packet); SDL_UnlockMutex(send_mutex); } } else { // If it's new, send it as a new entity // Check bounds if (dent.x + dent.w < -1024 || dent.x > 1024 || dent.y + dent.h < -1024 || dent.y > 1024) return; // Store it client_entities[eid] = dent; static const int len = 15; DataPacket packet = { len, new char[len] }; packet.data[0] = 'a'; SDLNet_Write16(dent.id, packet.data + 1); SDLNet_Write16(dent.x, packet.data + 3); SDLNet_Write16(dent.y, packet.data + 5); SDLNet_Write16(dent.z, packet.data + 7); SDLNet_Write16(dent.w, packet.data + 9); SDLNet_Write16(dent.h, packet.data + 11); SDLNet_Write16(dent.tex, packet.data + 13); SDL_LockMutex(send_mutex); data_to_send.push_back(packet); SDL_UnlockMutex(send_mutex); } }
// poll for new packets received, check that connection is alive, resend queued packets if necessary int network_check( void ) { #ifdef __BLACKBERRY__ #else if (!net_initialized) return -1; if (connected) { // timeout if (!network_is_alive()) { if (!quit) network_tyrian_halt(2, false); } // keep-alive static Uint32 keep_alive_tick = 0; if (SDL_GetTicks() - keep_alive_tick > NET_KEEP_ALIVE) { network_prepare(PACKET_KEEP_ALIVE); network_send_no_ack(4); keep_alive_tick = SDL_GetTicks(); } } // retry if (packet_out[0] && SDL_GetTicks() - last_out_tick > NET_RETRY) { if (!SDLNet_UDP_Send(socket, 0, packet_out[0])) { printf("SDLNet_UDP_Send: %s\n", SDL_GetError()); return -1; } last_out_tick = SDL_GetTicks(); } switch (SDLNet_UDP_Recv(socket, packet_temp)) { case -1: printf("SDLNet_UDP_Recv: %s\n", SDL_GetError()); return -1; break; case 0: break; default: if (packet_temp->channel == 0 && packet_temp->len >= 4) { switch (SDLNet_Read16(&packet_temp->data[0])) { case PACKET_ACKNOWLEDGE: if ((Uint16)(SDLNet_Read16(&packet_temp->data[2]) - last_ack_sync) < NET_PACKET_QUEUE) { last_ack_sync = SDLNet_Read16(&packet_temp->data[2]); } { Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_out_sync; if (i < NET_PACKET_QUEUE) { if (packet_out[i]) { SDLNet_FreePacket(packet_out[i]); packet_out[i] = NULL; } } } // remove acknowledged packets from queue while (packet_out[0] == NULL && (Uint16)(last_ack_sync - queue_out_sync) < NET_PACKET_QUEUE) { packets_shift_up(packet_out, NET_PACKET_QUEUE); queue_out_sync++; } last_in_tick = SDL_GetTicks(); break; case PACKET_CONNECT: queue_in_sync = SDLNet_Read16(&packet_temp->data[2]); for (int i = 0; i < NET_PACKET_QUEUE; i++) { if (packet_in[i]) { SDLNet_FreePacket(packet_in[i]); packet_in[i] = NULL; } } case PACKET_DETAILS: case PACKET_WAITING: case PACKET_BUSY: case PACKET_GAME_QUIT: case PACKET_GAME_PAUSE: case PACKET_GAME_MENU: { Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - queue_in_sync; if (i < NET_PACKET_QUEUE) { if (packet_in[i] == NULL) packet_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE); packet_copy(packet_in[i], packet_temp); } else { // inbound packet queue overflow/underflow // under normal circumstances, this is okay } } network_acknowledge(SDLNet_Read16(&packet_temp->data[2])); case PACKET_KEEP_ALIVE: last_in_tick = SDL_GetTicks(); break; case PACKET_QUIT: if (!quit) { network_prepare(PACKET_QUIT); network_send(4); // PACKET_QUIT } network_acknowledge(SDLNet_Read16(&packet_temp->data[2])); if (!quit) network_tyrian_halt(1, true); break; case PACKET_STATE: // place packet in queue if within limits { Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1; if (i < NET_PACKET_QUEUE) { if (packet_state_in[i] == NULL) packet_state_in[i] = SDLNet_AllocPacket(NET_PACKET_SIZE); packet_copy(packet_state_in[i], packet_temp); } } break; case PACKET_STATE_XOR: // place packet in queue if within limits { Uint16 i = SDLNet_Read16(&packet_temp->data[2]) - last_state_in_sync + 1; if (i < NET_PACKET_QUEUE) { if (packet_state_in_xor[i] == NULL) { packet_state_in_xor[i] = SDLNet_AllocPacket(NET_PACKET_SIZE); packet_copy(packet_state_in_xor[i], packet_temp); } else if (SDLNet_Read16(&packet_state_in_xor[i]->data[0]) != PACKET_STATE_XOR) { for (int j = 4; j < packet_state_in_xor[i]->len; j++) packet_state_in_xor[i]->data[j] ^= packet_temp->data[j]; SDLNet_Write16(PACKET_STATE_XOR, &packet_state_in_xor[i]->data[0]); } } } break; case PACKET_STATE_RESEND: // resend requested state packet if still available { Uint16 i = last_state_out_sync - SDLNet_Read16(&packet_temp->data[2]); if (i > 0 && i < NET_PACKET_QUEUE) { if (packet_state_out[i]) { if (!SDLNet_UDP_Send(socket, 0, packet_state_out[i])) { printf("SDLNet_UDP_Send: %s\n", SDL_GetError()); return -1; } } } } break; default: fprintf(stderr, "warning: bad packet %d received\n", SDLNet_Read16(&packet_temp->data[0])); return 0; break; } return 1; } break; } #endif return 0; }
// receive state packet, wait until received bool network_state_update( void ) { #ifdef __BLACKBERRY__ return false; #else if (network_state_is_reset()) { return 0; } else { packets_shift_up(packet_state_in, NET_PACKET_QUEUE); packets_shift_up(packet_state_in_xor, NET_PACKET_QUEUE); last_state_in_sync++; // current xor packet index int x = network_delay - (last_state_in_sync - 1) % network_delay - 1; // loop until needed packet is available while (!packet_state_in[0]) { // xor the packet from thin air, if possible if (packet_state_in_xor[x] && SDLNet_Read16(&packet_state_in_xor[x]->data[0]) == PACKET_STATE_XOR) { // check for all other required packets bool okay = true; for (int i = 1; i <= x; i++) { if (packet_state_in[i] == NULL) { okay = false; break; } } if (okay) { packet_state_in[0] = SDLNet_AllocPacket(NET_PACKET_SIZE); packet_copy(packet_state_in[0], packet_state_in_xor[x]); for (int i = 1; i <= x; i++) for (int j = 4; j < packet_state_in[0]->len; j++) packet_state_in[0]->data[j] ^= packet_state_in[i]->data[j]; break; } } static Uint32 resend_tick = 0; if (SDL_GetTicks() - last_state_in_tick > NET_RESEND && SDL_GetTicks() - resend_tick > NET_RESEND) { SDLNet_Write16(PACKET_STATE_RESEND, &packet_out_temp->data[0]); SDLNet_Write16(last_state_in_sync - 1, &packet_out_temp->data[2]); network_send_no_ack(4); // PACKET_RESEND resend_tick = SDL_GetTicks(); } if (network_check() == 0) SDL_Delay(1); } if (network_delay > 1) { // process the current in packet against the xor queue if (packet_state_in_xor[x] == NULL) { packet_state_in_xor[x] = SDLNet_AllocPacket(NET_PACKET_SIZE); packet_copy(packet_state_in_xor[x], packet_state_in[0]); packet_state_in_xor[x]->status = 0; } else { for (int j = 4; j < packet_state_in_xor[x]->len; j++) packet_state_in_xor[x]->data[j] ^= packet_state_in[0]->data[j]; } } last_state_in_tick = SDL_GetTicks(); } return 1; #endif }