123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582 |
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <string.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/prctl.h>
- #include <sys/time.h>
- #include <errno.h>
- #include "server.h"
- /*
- buf - buf for send to client
- list - global list of active players
- listSem - sem for lock global list
- myself - pointer to current player
- net proto
- server -> client
- <num objs u8> <obj desc u8> <obj pos u8> ....
- client -> server
- <intent u8>
- */
- static inline void gameTickProcessor( struct instance* this, char tick ){
-
- int s;
- int res;
- char buf[2];
- char cmd[2];
- struct tanksPlayer* myself;
- struct tanksPlayer* player;
- int tmpX;
- int tmpY;
-
- s = 1;
- this->situation[0] = 0;
-
-
- for( myself = this->players; myself; myself = myself->next ) {
-
- memset( cmd, 0, 2 );
-
- /********* recv intent *********/
-
- res = recv( myself->sock, buf, 2, MSG_WAITALL );
- if( res < 0 ){
- if( errno != EAGAIN || errno != EWOULDBLOCK ) perror( "recv intent" );
- goto l_handleIntent;
- }
-
- if( res != 2 ){
- printf( "WARNING: Too few bytes received!\n" );
- goto l_handleIntent;
- }
-
- if( buf[0] == 'g' ) myself->gearbox = buf[1];
- else memcpy( cmd, buf, 2 );
-
- /********* handle intent *********/
- l_handleIntent:
-
- //if player spectator
- if( !myself->rot ){
-
- //select spawn point
- if( cmd[0] == 's' ){
- if( cmd[1] == '1' ){
- myself->rot = 'd';
- myself->posX = 1;
- myself->posY = 10;
- }else if( cmd[1] == '2' ){
- myself->rot = 'd';
- myself->posX = 8;
- myself->posY = 10;
- }else if( cmd[1] == '3' ){
- myself->rot = 'u';
- myself->posX = 1;
- myself->posY = 180;
- }else if( cmd[1] == '4' ){
- myself->rot = 'u';
- myself->posX = 8;
- myself->posY = 180;
- }
- myself->gearbox = 0x00;
- }
-
- //if player alive
- } else {
-
- //if player blasting
- if( myself->blast ){
- if( tick ){
- myself->blast--;
- if( myself->blast ){
- if( myself->rot == 'B' ) myself->rot = 'b';
- else myself->rot = 'B';
- } else {
- myself->rot = 0x00;
- }
- }
-
- //if player send "fire" cmd
- } else if( cmd[0] == 'f' && !myself->shotRot ){
- myself->shotPosX = myself->posX;
- myself->shotPosY = myself->posY;
- myself->shotRot = myself->rot;
-
- //handle tank move
- } else if( tick && myself->gearbox ) {
-
- tmpX = myself->posX;
- tmpY = myself->posY;
-
- //move up
- if( myself->gearbox == 'u' ){
-
- if( myself->gearbox != myself->rot ) myself->rot = myself->gearbox;
- else if( tmpY > 10 ){
- tmpY -= 10;
-
- //check collision
- for( player = this->players; player; player = player->next ){
-
- if( !player->rot ) continue;
- if( player->blast ) continue;
- if( player->posX != tmpX - 2 &&
- player->posX != tmpX - 1 &&
- player->posX != tmpX &&
- player->posX != tmpX + 1 &&
- player->posX != tmpX + 2 ) continue;
-
- if( player->posY == tmpY - 20 ) goto l_skipMove;
- }
- }
-
- //move left
- }else if( myself->gearbox == 'l' ){
-
- if( myself->gearbox != myself->rot ) myself->rot = myself->gearbox;
- else if( tmpX > 1 ){
- tmpX--;
-
- //check collision
- for( player = this->players; player; player = player->next ){
-
- if( !player->rot ) continue;
- if( player->blast ) continue;
- if( player->posY != tmpY - 20 &&
- player->posY != tmpY - 10 &&
- player->posY != tmpY &&
- player->posY != tmpY + 10 &&
- player->posY != tmpY + 20 ) continue;
-
- if( player->posX == tmpX - 2 ) goto l_skipMove;
- }
- }
-
- //move down
- } else if( myself->gearbox == 'd' ){
-
- if( myself->gearbox != myself->rot ) myself->rot = myself->gearbox;
- else if( tmpY < 180 ){
- tmpY += 10;
-
- //check collision
- for( player = this->players; player; player = player->next ){
-
- if( !player->rot ) continue;
- if( player->blast ) continue;
- if( player->posX != tmpX - 2 &&
- player->posX != tmpX - 1 &&
- player->posX != tmpX &&
- player->posX != tmpX + 1 &&
- player->posX != tmpX + 2 ) continue;
-
- if( player->posY == tmpY + 20 ) goto l_skipMove;
- }
- }
-
- //move right
- }else if( myself->gearbox == 'r' ){
-
- if( myself->gearbox != myself->rot ) myself->rot = myself->gearbox;
- else if( tmpX < 8 ){
- tmpX++;
-
- //check collision
- for( player = this->players; player; player = player->next ){
-
- if( !player->rot ) continue;
- if( player->blast ) continue;
- if( player->posY != tmpY - 20 &&
- player->posY != tmpY - 10 &&
- player->posY != tmpY &&
- player->posY != tmpY + 10 &&
- player->posY != tmpY + 20 ) continue;
-
- if( player->posX == tmpX + 2 ) goto l_skipMove;
- }
- }
- }
-
- myself->posX = tmpX;
- myself->posY = tmpY;
- }//handle tank move
- }//if player alive
-
- l_skipMove:
-
- //add myself to situation
- if( myself->rot ){
- this->situation[0]++;
- this->situation[s] = myself->rot;
- s++;
- this->situation[s] = myself->posX + myself->posY;
- s++;
- }
-
- /********* move shot *********/
-
- if( myself->shotRot ){
- if( myself->shotRot == 'u' ){
- if( myself->shotPosY > 0 ) myself->shotPosY -= 10;
- else myself->shotRot = 0x00;
- }else if( myself->shotRot == 'l' ){
- if( myself->shotPosX > 0 ) myself->shotPosX--;
- else myself->shotRot = 0x00;
- }else if( myself->shotRot == 'd' ){
- if( myself->shotPosY < 190 ) myself->shotPosY += 10;
- else myself->shotRot = 0x00;
- }else if( myself->shotRot == 'r' ){
- if( myself->shotPosX < 9 ) myself->shotPosX++;
- else myself->shotRot = 0x00;
- }
-
- //check hit
- for( player = this->players; player; player = player->next ){
-
- if( !player->rot ) continue;
- if( player->blast ) continue;
- if( player == myself ) continue;
- if( player->posX != myself->shotPosX && player->posX - 1 != myself->shotPosX && player->posX + 1 != myself->shotPosX ) continue;
- if( player->posY != myself->shotPosY && player->posY - 10 != myself->shotPosY && player->posY + 10 != myself->shotPosY ) continue;
-
- player->blast = 16;
- player->rot = 'B';
- myself->shotRot = 0x00;
- break;
- }
-
- //add my shot to situation
- if( myself->shotRot ){
- this->situation[0]++;
- this->situation[s] = 'f';
- s++;
- this->situation[s] = myself->shotPosX + myself->shotPosY;
- s++;
- }
- }
- }
-
- }
- static inline void playerRegister( struct instance* this, struct tanksPlayer* newPlayer ){
- newPlayer->next = this->players;
- this->players = newPlayer;
- this->onlinePlayers++;
- }
- static inline void playerUnregister( struct instance* this, struct tanksPlayer* delPlayer ){
-
- struct tanksPlayer* player;
-
- if( this->players == delPlayer ) this->players = delPlayer->next;
- else {
- for( player = this->players; player; player = player->next ){
- if( player->next == delPlayer ){
- player->next = delPlayer->next;
- break;
- }
- }
- }
-
- this->onlinePlayers--;
-
- }
- /**************
- func openTcpPort
- prepare and open port
- in
- port - port No to listen
-
- return
- neg on err
- else port fd
- ***************/
- static int openTcpPort( unsigned short port ){
-
- int res;
- int serverSocket;
- const int reuseAddrEnable = 1;
- struct sockaddr_in addr;
-
- //socket
- serverSocket = socket( AF_INET, SOCK_STREAM, 0 );
- if( serverSocket < 0 ){
- perror( "socket" );
- return -2;
- }
-
- //set reuseaddr opt
- res = setsockopt( serverSocket, SOL_SOCKET, SO_REUSEADDR, &reuseAddrEnable, sizeof(reuseAddrEnable) );
- if( res ){
- perror( "server sock set SO_REUSEADDR" );
- goto l_err;
- }
-
- //mark non block
- res = fcntl( serverSocket, F_SETFL, O_NONBLOCK );
- if( res ){
- perror( "server sock set O_NONBLOCK" );
- goto l_err;
- }
-
- //prepare to bind
- memset ( &addr, 0, sizeof(addr) );
- addr.sin_family = AF_INET;
- addr.sin_port = htons( port );
- addr.sin_addr.s_addr = htonl( INADDR_ANY );
-
- //bind
- res = bind( serverSocket, (struct sockaddr*)&addr, sizeof(addr) );
- if( res < 0 ){
- perror( "bind" );
- goto l_err;
- }
-
- //listen
- res = listen( serverSocket, 5 );
- if( res ){
- perror( "listen" );
- goto l_err;
- }
-
- return serverSocket;
-
- l_err:
- close( serverSocket );
- return -2;
- }
- /**********************************
- func acceptPlayer
- accept pending connection, alloc
- new player and register him
- input
- this - server instance
-
- return
- 0 - ok
- neg on err
- *************************************/
- static inline int acceptPlayer( struct instance* this ){
-
- int res;
- int sock;
- char buf[8];
- struct tanksPlayer* player;
-
- //max players
- if( this->onlinePlayers > 4 ) return 0;
-
- /*** CONNECT ***/
-
- //accept
- sock = accept( this->serverSocket, NULL, NULL );
- if( sock < 0 ){
- if( errno == EAGAIN || errno == EWOULDBLOCK ) return 0;
- perror( "accept" );
- close( this->serverSocket );
- return -2;
- }
-
- //mark player sock non block
- res = fcntl( sock, F_SETFL, O_NONBLOCK );
- if( res ){
- perror( "player sock set O_NONBLOCK (not fatal)" );
- close( sock );
- return 0;
- }
-
- /*** HANDSHAKE ***/
-
- res = read( sock, buf, 5 );
- if( res < 0 ) goto l_drop;
-
- buf[5] = 0x00;
- if( strcmp(buf, "TANKS") ) goto l_drop;
-
- res = write( sock, "OK", 2 );
- if( res != 2 ) goto l_drop;
-
- /*** REGISTER ***/
-
- //alloc player
- player = malloc( sizeof(*player) );
- if( !player ){
- printf( "ERROR: cannot allocate new player(not fatal).\n" );
- close( sock );
- return 0;
- }
-
- //init player
- memset( player, 0, sizeof(*player) );
- player->sock = sock;
-
- //register player
- playerRegister( this, player );
-
- printf( "Connected %i\n", sock );
- return 0;
-
-
- //handshake failed
- l_drop:
- printf( "%i handhake failed\n", sock );
- close( sock );
- return 0;
- }
- static inline void sendSituation2Players( struct instance* this ){
-
- int res;
- int bytes;
- //unsigned char buf[2];
- struct tanksPlayer* kick;
- struct tanksPlayer* myself;
-
- bytes = (this->situation[0] * 2) + 1;
- myself = this->players;
-
- l_next:
-
- if( !myself ) return;
-
- /*** SEND ***/
-
- res = write( myself->sock, this->situation, bytes );
- if( res < 0 ){
- perror( "send" );
- if( errno == EAGAIN || errno == EWOULDBLOCK ) goto l_iterDone;
- goto l_kick;
-
- }
-
- if( res != bytes ){
- printf( "send err\n" );
- goto l_kick;
- }
-
- l_iterDone:
- myself = myself->next;
- goto l_next;
-
- l_kick:
-
- kick = myself;
- myself = myself->next;
-
- //del from list
- playerUnregister( this, kick );
-
- //close socket
- close( kick->sock );
- printf( "Disconnected %i\n", kick->sock );
-
- //free()
- free( kick );
-
- goto l_next;
- }
- static int mainLoop( unsigned short port ){
-
- int res;
- char tick;
- struct instance this;
- struct timeval startTime;
- struct timeval endTime;
- long long int sleepTime;
-
- tick = 0x00;
-
-
- /*** PREPARE ***/
- //init instance
- memset( &this, 0, sizeof(this) );
-
- //open port
- this.serverSocket = openTcpPort( port );
- if( this.serverSocket < 0 ) return this.serverSocket;
-
- printf( "Listen %hu TCP...\n", port );
-
- /*** WORK PROCESS ***/
- l_work:
-
- //start time
- gettimeofday( &startTime, NULL );
-
- //accept
- res = acceptPlayer( &this );
- if( res ) return -2;
-
- //game tick
- gameTickProcessor( &this, tick );
- tick = ~tick;
-
- //communicate
- sendSituation2Players( &this );
-
- //end time
- gettimeofday( &endTime, NULL );
-
- //sleep
- sleepTime = 40000 - ((endTime.tv_usec+((endTime.tv_sec-startTime.tv_sec)*1000000))-startTime.tv_usec);
- if( sleepTime > 0 ) usleep( sleepTime );
- else printf( "WARNING: overload.\n" );
-
- //continue
- goto l_work;
- }
- int main( int argc, char* argv[], char* envp[] ){
-
- int i;
- int res;
- unsigned short port;
-
- port = 0;
-
- //ignore sigpipe
- signal( SIGPIPE, SIG_IGN );
-
- //base check
- if( argc < 2 ) {
- l_help:
- printf( "usage:\n\t%s -p <TCP port>\n", argv[0] );
- return 2;
- }
-
- //parse arguments
- for( i = 1; i < argc; i++ ){
-
- if( !strcmp(argv[i], "-p") ){
- i++;
- if( i == argc ) goto l_help;
- res = sscanf( argv[i], "%hu", &port );
- if( res != 1 ) goto l_help;
- }
- }
-
- //check parsed values
- if( !port ) goto l_help;
-
- //start server
- mainLoop( port );
-
- return 0;
- }
|