/* Emacs style mode select -*- C++ -*- *----------------------------------------------------------------------------- * * * PrBoom: a Doom port merged with LxDoom and LSDLDoom * based on BOOM, a modified and improved DOOM engine * Copyright (C) 1999 by * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman * Copyright (C) 1999-2000 by * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze * Copyright 2005, 2006 by * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * DESCRIPTION: * Low level UDP network interface. This is shared between the server * and client, with SERVER defined for the former to select some extra * functions. Handles socket creation, and packet send and receive. * *-----------------------------------------------------------------------------*/ //#ifdef HAVE_CONFIG_H # include "config.h" //#endif #ifdef HAVE_NETINET_IN_H # include #endif #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #ifdef HAVE_NET #include "SDL.h" #include "SDL_net.h" #include "protocol.h" #include "i_network.h" #include "lprintf.h" //#include "doomstat.h" /* cph - * Each client will either use the IPv4 socket or the IPv6 socket * Each server will use whichever or both that are available */ UDP_CHANNEL sentfrom; IPaddress sentfrom_addr; UDP_SOCKET udp_socket; /* Statistics */ size_t sentbytes, recvdbytes; UDP_PACKET *udp_packet; /* I_ShutdownNetwork * * Shutdown the network code */ void I_ShutdownNetwork(void) { SDLNet_FreePacket(udp_packet); SDLNet_Quit(); } /* I_InitNetwork * * Sets up the network code */ void I_InitNetwork(void) { if ( SDLNet_Init() < 0 ) { I_Error("Unable to initialize network: %s", SDL_GetError()); } atexit(I_ShutdownNetwork); udp_packet = SDLNet_AllocPacket(10000); if ( udp_packet == NULL ) { I_Error("Unable to allocate network packet: %s", SDL_GetError()); } } UDP_PACKET *I_AllocPacket(int size) { return(SDLNet_AllocPacket(size)); } void I_FreePacket(UDP_PACKET *packet) { SDLNet_FreePacket(packet); } /* cph - I_WaitForPacket - use select(2) via SDL_net's interface * No more I_uSleep loop kludge */ void I_WaitForPacket(int ms) { SDLNet_SocketSet ss = SDLNet_AllocSocketSet(1); SDLNet_UDP_AddSocket(ss, udp_socket); SDLNet_CheckSockets(ss,ms); SDLNet_FreeSocketSet(ss); #if (defined _WIN32 && !defined PRBOOM_SERVER) I_UpdateConsole(); #endif } /* I_ConnectToServer * * Connect to a server */ IPaddress serverIP; int I_ConnectToServer(const char *serv) { char server[500], *p; Uint16 port; /* Split serv into address and port */ if (strlen(serv)>500) return 0; strcpy(server,serv); p = strchr(server, ':'); if(p) { *p++ = '\0'; port = atoi(p); } else port = 5030; /* Default server port */ SDLNet_ResolveHost(&serverIP, server, port); if ( serverIP.host == INADDR_NONE ) return -1; if (SDLNet_UDP_Bind(udp_socket, 0, &serverIP) == -1) return -1; return 0; } /* I_Disconnect * * Disconnect from server */ void I_Disconnect(void) { /* int i; UDP_PACKET *packet; packet_header_t *pdata = (packet_header_t *)packet->data; packet = I_AllocPacket(sizeof(packet_header_t) + 1); packet->data[sizeof(packet_header_t)] = consoleplayer; pdata->type = PKT_QUIT; pdata->tic = gametic; for (i=0; i<4; i++) { I_SendPacket(packet); I_uSleep(10000); } I_FreePacket(packet);*/ SDLNet_UDP_Unbind(udp_socket, 0); } /* * I_Socket * * Sets the given socket non-blocking, binds to the given port, or first * available if none is given */ UDP_SOCKET I_Socket(Uint16 port) { if(port) return (SDLNet_UDP_Open(port)); else { UDP_SOCKET sock; port = IPPORT_RESERVED; while( (sock = SDLNet_UDP_Open(port)) == NULL ) port++; return sock; } } void I_CloseSocket(UDP_SOCKET sock) { SDLNet_UDP_Close(sock); } UDP_CHANNEL I_RegisterPlayer(IPaddress *ipaddr) { static int freechannel; return(SDLNet_UDP_Bind(udp_socket, freechannel++, ipaddr)); } void I_UnRegisterPlayer(UDP_CHANNEL channel) { SDLNet_UDP_Unbind(udp_socket, channel); } /* * ChecksumPacket * * Returns the checksum of a given network packet */ static byte ChecksumPacket(const packet_header_t* buffer, size_t len) { const byte* p = (const void*)buffer; byte sum = 0; if (len==0) return 0; while (p++, --len) sum += *p; return sum; } size_t I_GetPacket(packet_header_t* buffer, size_t buflen) { int checksum; size_t len; int status; status = SDLNet_UDP_Recv(udp_socket, udp_packet); len = udp_packet->len; if (buflen0) ) memcpy(buffer, udp_packet->data, len); sentfrom=udp_packet->channel; #ifndef SDL_NET_UDP_PACKET_SRC sentfrom_addr=udp_packet->address; #else sentfrom_addr=udp_packet->src; /* cph - allow for old SDL_net library */ #endif checksum=buffer->checksum; buffer->checksum=0; if ( (status!=0) && (len>0)) { byte psum = ChecksumPacket(buffer, udp_packet->len); /* fprintf(stderr, "recvlen = %u, stolen = %u, csum = %u, psum = %u\n", udp_packet->len, len, checksum, psum); */ if (psum == checksum) return len; } return 0; } void I_SendPacket(packet_header_t* packet, size_t len) { packet->checksum = ChecksumPacket(packet, len); memcpy(udp_packet->data, packet, udp_packet->len = len); SDLNet_UDP_Send(udp_socket, 0, udp_packet); } void I_SendPacketTo(packet_header_t* packet, size_t len, UDP_CHANNEL *to) { packet->checksum = ChecksumPacket(packet, len); memcpy(udp_packet->data, packet, udp_packet->len = len); SDLNet_UDP_Send(udp_socket, *to, udp_packet); } void I_PrintAddress(FILE* fp, UDP_CHANNEL *addr) { /* char *addy; Uint16 port; IPaddress *address; address = SDLNet_UDP_GetPeerAddress(udp_socket, player); //FIXME: if it cant resolv it may freeze up addy = SDLNet_ResolveIP(address); port = address->port; if(addy != NULL) fprintf(fp, "%s:%d", addy, port); else fprintf(fp, "Error"); */ } #endif /* HAVE_NET */