X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fnetserv.c;h=4b846f9da413425db5e86999fd149111f34ea77c;hp=08d161023dbf20312319899a9161b853bac9a1fd;hb=d2bb945e958e551ee43005160e671db37899e8cb;hpb=0ff3f484ffbb8e3404e1dc4536a292335369f2d2 diff --git a/src/netserv.c b/src/netserv.c index 08d16102..4b846f9d 100644 --- a/src/netserv.c +++ b/src/netserv.c @@ -1,41 +1,31 @@ -/*********************************************************** -* Rocks'n'Diamonds -- McDuffin Strikes Back! * -*----------------------------------------------------------* -* (c) 1995-2002 Artsoft Entertainment * -* Holger Schemel * -* Detmolder Strasse 189 * -* 33604 Bielefeld * -* Germany * -* e-mail: info@artsoft.org * -*----------------------------------------------------------* -* network.c * -***********************************************************/ - -#include "libgame/platform.h" - -#if defined(PLATFORM_UNIX) +// ============================================================================ +// Rocks'n'Diamonds - McDuffin Strikes Back! +// ---------------------------------------------------------------------------- +// (c) 1995-2014 by Artsoft Entertainment +// Holger Schemel +// info@artsoft.org +// http://www.artsoft.org/ +// ---------------------------------------------------------------------------- +// netserv.c +// ============================================================================ #include #include #include -#include #include -#include -#include -#include -#include -#include /* apparently needed for OS/2 port */ #include "libgame/libgame.h" #include "netserv.h" +#include "main.h" + static int clients = 0; static int onceonly = 0; struct NetworkServerPlayerInfo { - int fd; + TCPsocket fd; char player_name[16]; unsigned char number; struct NetworkServerPlayerInfo *next; @@ -52,16 +42,16 @@ static struct NetworkServerPlayerInfo *first_player = NULL; #define NEXT(player) ((player)->next ? (player)->next : first_player) -static struct sockaddr_in saddr; -static int lfd; +/* TODO: peer address */ +static TCPsocket lfd; /* listening TCP socket */ +static UDPsocket udp; /* listening UDP socket */ +static SDLNet_SocketSet fds; /* socket set */ + static unsigned char realbuffer[512], *buffer = realbuffer + 4; static int interrupt; -static int tcp = -1; -static unsigned long ServerFrameCounter = 0; - -static fd_set fds; +static unsigned int ServerFrameCounter = 0; static void addtobuffer(struct NetworkServerPlayerInfo *player, unsigned char *b, int len) @@ -78,7 +68,8 @@ static void flushuser(struct NetworkServerPlayerInfo *player) { if (player->nwrite) { - write(player->fd, player->writbuffer, player->nwrite); + SDLNet_TCP_Send(player->fd, player->writbuffer, player->nwrite); + player->nwrite = 0; } } @@ -124,7 +115,9 @@ static void RemovePlayer(struct NetworkServerPlayerInfo *player) } } } - close(player->fd); + + SDLNet_TCP_DelSocket(fds, player->fd); + SDLNet_TCP_Close(player->fd); if (player->introduced) { @@ -136,6 +129,7 @@ static void RemovePlayer(struct NetworkServerPlayerInfo *player) free(player); clients--; +#if 0 /* do not terminate network server if last player disconnected */ if (onceonly && clients == 0) { if (options.verbose) @@ -145,9 +139,10 @@ static void RemovePlayer(struct NetworkServerPlayerInfo *player) } exit(0); } +#endif } -static void AddPlayer(int fd) +static void AddPlayer(TCPsocket fd) { struct NetworkServerPlayerInfo *player, *v; unsigned char nxn; @@ -165,11 +160,12 @@ static void AddPlayer(int fd) player->action = 0; player->action_received = FALSE; + SDLNet_TCP_AddSocket(fds, fd); + first_player = player; nxn = 1; -#if 1 while (again) { again = FALSE; @@ -187,24 +183,8 @@ static void AddPlayer(int fd) v = v->next; } } -#else - again: - v = player->next; - while (v) - { - if (v->number == nxn) - { - nxn++; - goto again; - } - v = v->next; - } -#endif player->number = nxn; - if (options.verbose) - Error(ERR_NETWORK_SERVER, "client %d connecting from %s", - nxn, inet_ntoa(saddr.sin_addr)); clients++; buffer[0] = 0; @@ -271,11 +251,11 @@ static void Handle_OP_NUMBER_WANTED(struct NetworkServerPlayerInfo *player) Error(ERR_NETWORK_SERVER, "client %d (%s) switches to # %d", player->number, player->player_name, nr_wanted); else if (player->number == nr_wanted) - Error(ERR_NETWORK_SERVER, "client %d (%s) still has # %d", + Error(ERR_NETWORK_SERVER, "client %d (%s) already has # %d", player->number, player->player_name, nr_wanted); else Error(ERR_NETWORK_SERVER, - "client %d (%s) cannot switch (client %d still exists)", + "client %d (%s) cannot switch (client %d already exists)", player->number, player->player_name, nr_wanted); } @@ -353,11 +333,11 @@ static void Handle_OP_START_PLAYING(struct NetworkServerPlayerInfo *player) if (options.verbose) Error(ERR_NETWORK_SERVER, - "client %d (%s) starts game [level %d from levedir %d (%s)]", + "client %d (%s) starts game [level %d from leveldir %d (%s)]", player->number, player->player_name, (buffer[2] << 8) + buffer[3], (buffer[4] << 8) + buffer[5], - &buffer[6]); + &buffer[10]); for (w = first_player; w; w = w->next) if (w->introduced) @@ -366,6 +346,8 @@ static void Handle_OP_START_PLAYING(struct NetworkServerPlayerInfo *player) /* reset frame counter */ ServerFrameCounter = 0; + Error(ERR_NETWORK_SERVER, "resetting ServerFrameCounter to 0"); + /* reset player actions */ for (v = first_player; v; v = v->next) { @@ -394,10 +376,12 @@ static void Handle_OP_CONTINUE_PLAYING(struct NetworkServerPlayerInfo *player) static void Handle_OP_STOP_PLAYING(struct NetworkServerPlayerInfo *player) { + int cause_for_stopping = buffer[2]; + if (options.verbose) - Error(ERR_NETWORK_SERVER, "client %d (%s) stops game", - player->number, player->player_name); - broadcast(NULL, 2, 0); + Error(ERR_NETWORK_SERVER, "client %d (%s) stops game [%d]", + player->number, player->player_name, cause_for_stopping); + broadcast(NULL, 3, 0); } static void Handle_OP_MOVE_PLAYER(struct NetworkServerPlayerInfo *player) @@ -448,77 +432,78 @@ static void Handle_OP_MOVE_PLAYER(struct NetworkServerPlayerInfo *player) ServerFrameCounter++; } +void ExitNetworkServer(int exit_value) +{ + Error(ERR_NETWORK_SERVER, "exiting network server"); + + exit(exit_value); +} + +/* the following is not used for a standalone server; + the pointer points to an integer containing the port-number */ +int NetworkServerThread(void *ptr) +{ + NetworkServer(*((int *) ptr), 0); + + /* should never be reached */ + return 0; +} + void NetworkServer(int port, int serveronly) { - int i, sl, on; struct NetworkServerPlayerInfo *player; - int mfd; int r; unsigned int len; - struct protoent *tcpproto; - struct timeval tv; - int is_daemon = 0; + IPaddress ip; -#ifndef NeXT +#if defined(PLATFORM_UNIX) && !defined(PLATFORM_NEXT) struct sigaction sact; #endif if (port == 0) port = DEFAULT_SERVER_PORT; + // if only running the network server, exit on Ctrl-C + if (serveronly) + signal(SIGINT, ExitNetworkServer); + if (!serveronly) onceonly = 1; - if ((tcpproto = getprotobyname("tcp")) != NULL) - tcp = tcpproto->p_proto; - -#ifdef NeXT +#if defined(PLATFORM_UNIX) +#if defined(PLATFORM_NEXT) signal(SIGPIPE, SIG_IGN); #else sact.sa_handler = SIG_IGN; sigemptyset(&sact.sa_mask); sact.sa_flags = 0; sigaction(SIGPIPE, &sact, NULL); +#endif #endif + if (SDLNet_ResolveHost(&ip, NULL, port) == -1) + Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_ResolveHost() failed: %s", + SDLNet_GetError()); - if ((lfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) - Error(ERR_EXIT_NETWORK_SERVER, "socket() failed"); - - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = htonl(INADDR_ANY); - saddr.sin_port = htons(port); - - on = 1; + if ((fds = SDLNet_AllocSocketSet(MAX_PLAYERS + 1 + 1)) == NULL) + Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_AllocSocketSet() failed: %s"), + SDLNet_GetError(); - setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)); - if (bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) - Error(ERR_EXIT_NETWORK_SERVER, "bind() failed"); + if ((lfd = SDLNet_TCP_Open(&ip)) == NULL) + Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_Open() failed: %s"), + SDLNet_GetError(); - listen(lfd, 5); + if (SDLNet_TCP_AddSocket(fds, lfd) == -1) + Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_AddSocket() failed: %s"), + SDLNet_GetError(); - if (is_daemon) - { - /* become a daemon, breaking all ties with the controlling terminal */ - options.verbose = FALSE; - for (i = 0; i < 255; i++) - { - if (i != lfd) - close(i); - } + if ((udp = SDLNet_UDP_Open(port)) == NULL) + Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_UDP_Open() failed: %s", + SDLNet_GetError()); - if (fork()) - exit(0); - setsid(); - if (fork()) - exit(0); - chdir("/"); - - /* open a fake stdin, stdout, stderr, just in case */ - open("/dev/null", O_RDONLY); - open("/dev/null", O_WRONLY); - open("/dev/null", O_WRONLY); - } + if (SDLNet_UDP_AddSocket(fds, udp) == -1) + Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_AddSocket() failed: %s"), + SDLNet_GetError(); if (options.verbose) { @@ -534,63 +519,49 @@ void NetworkServer(int port, int serveronly) for (player = first_player; player; player = player->next) flushuser(player); - FD_ZERO(&fds); - mfd = lfd; - player = first_player; - while (player) + // wait for 100 ms for activity on open network sockets + if (SDLNet_CheckSockets(fds, 100) < 1) + continue; + + /* accept incoming TCP connections */ + if (SDLNet_SocketReady(lfd)) { - FD_SET(player->fd, &fds); - if (player->fd > mfd) - mfd = player->fd; - player = player->next; + Error(ERR_DEBUG, "got TCP packet"); + + TCPsocket newsock; + + newsock = SDLNet_TCP_Accept(lfd); + + if (newsock) + AddPlayer(newsock); } - FD_SET(lfd, &fds); - tv.tv_sec = 0; - tv.tv_usec = 500000; - if ((sl = select(mfd + 1, &fds, NULL, NULL, &tv)) < 0) + + /* accept incoming UDP packets */ + if (SDLNet_SocketReady(udp)) { - if (errno != EINTR) - Error(ERR_EXIT_NETWORK_SERVER, "select() failed"); - else - continue; - } + Error(ERR_DEBUG, "got UDP packet"); - if (sl < 0) - continue; - - if (sl == 0) - continue; + static UDPpacket packet; - if (FD_ISSET(lfd, &fds)) - { - int newfd, slen; + int num_packets = SDLNet_UDP_Recv(udp, &packet); - slen = sizeof(saddr); - newfd = accept(lfd, (struct sockaddr *)&saddr, &slen); - if (newfd < 0) + if (num_packets == 1) { - if (errno != EINTR) - Error(ERR_EXIT_NETWORK_SERVER, "accept() failed"); + // bounce packet + SDLNet_UDP_Send(udp, -1, &packet); } - else - { - if (tcp != -1) - { - on = 1; - setsockopt(newfd, tcp, TCP_NODELAY, (char *)&on, sizeof(int)); - } - AddPlayer(newfd); - } - continue; } player = first_player; - do + while (player && !interrupt) { - if (FD_ISSET(player->fd, &fds)) + if (SDLNet_SocketReady(player->fd)) { - r = read(player->fd, player->readbuffer + player->nread, MAX_BUFFER_SIZE - player->nread); + /* read only 1 byte, because SDLNet blocks when we want more than is + in the buffer */ + r = SDLNet_TCP_Recv(player->fd, player->readbuffer + player->nread, 1); + if (r <= 0) { if (options.verbose) @@ -618,17 +589,19 @@ void NetworkServer(int port, int serveronly) memmove(player->readbuffer, player->readbuffer + 4 + len, player->nread); buffer[0] = player->number; - if (!player->introduced && buffer[1] != OP_PLAYER_NAME) + if (!player->introduced && + buffer[1] != OP_PLAYER_NAME && + buffer[1] != OP_PROTOCOL_VERSION) { if (options.verbose) - Error(ERR_NETWORK_SERVER, "!(client %d)->introduced && buffer[1]==%d (expected OP_PLAYER_NAME)", buffer[0], buffer[1]); + Error(ERR_NETWORK_SERVER, "!(client %d)->introduced && buffer[1]==%d (expected OP_PLAYER_NAME or OP_PROTOCOL_VERSION)", buffer[0], buffer[1]); RemovePlayer(player); interrupt = 1; break; } - switch(buffer[1]) + switch (buffer[1]) { case OP_PLAYER_NAME: Handle_OP_PLAYER_NAME(player, len); @@ -682,8 +655,5 @@ void NetworkServer(int port, int serveronly) if (player && !interrupt) player = player->next; } - while (player && !interrupt); } } - -#endif /* PLATFORM_UNIX */