/* * Biloba * Copyright (C) 2004-2005 Guillaume Demougeot, Colin Leroy * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /** * Biloba - Q1 2005 * Game by Guillaume Demougeot * Code by Colin Leroy * * This file contains all the network client code. */ #include #include #include #include #ifndef __MINGW32__ #include #include #include #else #include #endif #include #include #include #include "utils.h" #include "player.h" #include "net.h" #include "netops.h" #include "font.h" #include "game.h" #include "keyboard.h" #include "msg.h" #undef NET_DEBUG void net_init(void) { #ifdef __MINGW32__ WSADATA wsaData; WSAStartup(MAKEWORD(2,0),&wsaData); #endif } void net_stop(void) { #ifdef __MINGW32__ WSACleanup(); #endif } #ifdef __MINGW32__ #define INVSOCK INVALID_SOCKET #else #define INVSOCK -1 #endif static int game_running = FALSE; static int mysock = INVSOCK; static int mygameid = -1; #ifdef __MINGW32__ void debug_err(int y, int err) { switch(err) { case WSANOTINITIALISED: draw_message("WSANOTINITIALISED", 300, y, FALSE); break; case WSAENETDOWN: draw_message("WSAENETDOWN", 300, y, FALSE); break; case WSAEAFNOSUPPORT: draw_message("WSAEAFNOSUPPORT", 300, y, FALSE); break; case WSAEINPROGRESS: draw_message("WSAEINPROGRESS", 300, y, FALSE); break; case WSAEMFILE: draw_message("WSAEMFILE", 300, y, FALSE); break; case WSAENOBUFS: draw_message("WSAENOBUFS", 300, y, FALSE); break; case WSAEPROTONOSUPPORT: draw_message("WSAEPROTONOSUPPORT", 300, y, FALSE); break; case WSAEPROTOTYPE: draw_message("WSAEPROTOTYPE", 300, y, FALSE); break; case WSAESOCKTNOSUPPORT: draw_message("WSAESOCKTNOSUPPORT", 300, y, FALSE); break; default: draw_message("UNKNOWN", 300, y, FALSE); } } #endif int sock_connect(const char *hostname, unsigned short port) { int sockfd = INVSOCK; struct hostent *server; struct sockaddr_in serv_addr; int err; sockfd = socket(AF_INET, SOCK_STREAM, 0); #ifndef __MINGW32__ if (sockfd < 0) { #else if (sockfd == INVALID_SOCKET) { #endif #ifdef NET_DEBUG draw_message("socket error", 10, 10, FALSE); #ifdef __MINGW32__ err = WSAGetLastError(); debug_err(10, err); #endif SDL_Delay(200); #endif return -1; } else { #ifdef NET_DEBUG draw_message("socket ok", 10, 10, FALSE); SDL_Delay(200); #endif } server = gethostbyname(hostname); if (server == NULL) { #ifdef NET_DEBUG draw_message("gethostbyname error", 10, 42, FALSE); #ifdef __MINGW32__ err = WSAGetLastError(); debug_err(42, err); #endif SDL_Delay(200); #endif return -1; } else { #ifdef NET_DEBUG draw_message("gethostbyname ok", 10, 42, FALSE); SDL_Delay(200); #endif } memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; memcpy(&serv_addr.sin_addr, server->h_addr, server->h_length); serv_addr.sin_port = htons(port); printf("connecting\n"); err = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); #ifndef __MINGW32__ if (err < 0) { #else if (err == INVALID_SOCKET) { #endif #ifdef NET_DEBUG draw_message("connect error", 10, 74, FALSE); #ifdef __MINGW32__ err = WSAGetLastError(); debug_err(74, err); #endif SDL_Delay(200); #endif printf("connect error: %d\n", err); return -1; } else { #ifdef NET_DEBUG draw_message("connect ok", 10, 74, FALSE); SDL_Delay(200); #endif } printf("connected: fd %d\n", sockfd); return (sockfd); } #define CHECK_MSG(str) { \ read_msg(mysock, buf, 255, &len); \ buf[254] = '\0'; \ if (strncmp(buf, str, strlen(str))) { \ printf("Unexpected reply \"%s\"", \ buf); \ goto err_protocol; \ } \ } #define DUMP(buf) {\ int k=0;\ for(k=0; k < 255; k++)\ printf("%c(%d) ",buf[k],buf[k]);\ printf("\n");\ } int net_init_game(const char *gamename, int numplayers, InputSystemMethod p0method, const char *p0name, InputSystemMethod p1method, const char *p1name, InputSystemMethod p2method, const char *p2name, InputSystemMethod p3method, const char *p3name) { char buf[255]; unsigned char len = 0; int i = 0; unsigned int gameid; assert(game_running == FALSE); SDL_FillRect(screen, NULL, 0x00000000); SDL_UpdateRect(screen, 0, 0, 0, 0); mysock = sock_connect(net_get_server(), NET_PORT); printf("INIT: sock %d\n", mysock); #ifndef __MINGW32__ if (mysock < 0) goto err_socket; #else if (mysock == INVALID_SOCKET) goto err_socket; #endif /* init connection */ send_msg(mysock, "NEWGAME", strlen("NEWGAME")+1); printf("INIT> NEWGAME\n"); CHECK_MSG("OK"); printf("INIT< OK\n"); /* send name */ assert(strlen(gamename) < 255); send_msg(mysock, gamename, (unsigned char)strlen(gamename)+1); printf("INIT> %s\n", gamename); /* get id */ read_msg(mysock, &gameid, 4, &len); if (len > 4) { printf("unexpected len %d on id\n", len); goto err_protocol; } mygameid = ntohl(gameid); printf("INIT< %d (game id)\n", mygameid); #ifdef NET_DEBUG printf("mygameid: %d\n", mygameid); #endif /* send nump, methods and names */ buf[i] = (unsigned char)numplayers; i++; buf[i] = (unsigned char)p0method; i++; strcpy(buf+i, p0name); i+=strlen(p0name)+1; buf[i] = (unsigned char)p1method; i++; strcpy(buf+i, p1name); i+=strlen(p1name)+1; if(numplayers > 2) { buf[i] = (unsigned char)p2method; i++; strcpy(buf+i, p2name); i+=strlen(p2name)+1; } if(numplayers > 3) { buf[i] = (unsigned char)p3method; i++; strcpy(buf+i, p3name); i+=strlen(p3name)+1; } send_msg(mysock, buf, i); printf("INIT> PLAYER NAMES AND TYPES\n"); CHECK_MSG("READY"); printf("INIT< READY\n"); return mygameid; err_protocol: close(mysock); err_socket: mysock = INVSOCK; mygameid = -1; return -1; } static SDL_Thread *kb_thread = NULL; static int run_kb_thread = FALSE; static int key = 0, mod = 0; static int kb_grab(void *data) { assert(run_kb_thread == FALSE); key = mod = 0; run_kb_thread = TRUE; while (run_kb_thread) { SDL_Event event; if (SDL_PollEvent(&event)) { if (event.type == SDL_KEYUP) { SDL_KeyboardEvent *kevent = &event.key; if (kevent->keysym.sym && kevent->keysym.mod) { key = kevent->keysym.sym; mod = kevent->keysym.mod; } } else if (event.type == SDL_QUIT) { key = SDLK_q; mod = KMOD_CTRL; } } SDL_Delay(50); } return 0; } int net_wait_ready(int num_players, char **player_names) { int waiting = 0, prev_waiting = 0; unsigned char len = 0; char buf[255], player[255]; int nplayer, i; int tmp = 0; #ifndef __MINGW32__ assert(mysock > 0); #else assert(mysock != INVALID_SOCKET); #endif kb_thread = SDL_CreateThread(kb_grab, NULL); do { if (send_msg(mysock, "READY?", 7) < 0) goto err_out; if (read_msg(mysock, &waiting, 4, &len) < 0) goto err_out; waiting = ntohl(waiting); sprintf(buf, get_msg(M_WAITING), waiting, waiting > 1 ? "s":""); SDL_FillRect(screen, NULL, 0x00000000); SDL_UpdateRect(screen, 0, 0, 0, 0); draw_message(buf, 150, 284, FALSE); if (read_msg(mysock, &nplayer, 4, &len) < 0) goto err_out; nplayer = ntohl(nplayer); if (read_msg(mysock, &player, 255, &len) < 0) goto err_out; player[254] = '\0'; if (prev_waiting > waiting) { sprintf(buf, get_msg(M_JOINED), player); draw_message(buf, 150, 284 + 40, FALSE); printf("%d: %s\n", nplayer, player); strcpy(player_names[nplayer], player); SDL_Delay(1000); } if (key == SDLK_q && (mod & KMOD_CTRL)) { keyboard_push_event(key, mod); } if (should_quit()) goto err_out; prev_waiting = waiting; SDL_Delay(1000); } while (waiting > 0); run_kb_thread = FALSE; SDL_WaitThread(kb_thread, &tmp); kb_thread = NULL; for (i = 0; i < num_players; i++) { if (read_msg(mysock, &player, 255, &len) < 0) return -1; player[254] = '\0'; strcpy(player_names[i], player); } return 0; err_out: run_kb_thread = FALSE; SDL_WaitThread(kb_thread, &tmp); kb_thread = NULL; return -1; } LList *net_get_games(int numplayer) { char buf[255]; unsigned char len = 0; int i = 0, numgames = 0; LList *games = NULL; assert(game_running == FALSE); #ifndef __MINGW32 if (mysock > 0) { #else if (mysock != INVALID_SOCKET) { #endif close(mysock); mysock = INVSOCK; } mysock = sock_connect(net_get_server(), NET_PORT); printf("LISTGAME: sock %d\n", mysock); #ifndef __MINGW32__ if (mysock < 0) goto err_socket; #else if (mysock == INVALID_SOCKET) goto err_socket; #endif /* init connection */ send_msg(mysock, "LISTGAME", strlen("LISTGAME")+1); printf("LISTGAME> LISTGAME\n"); CHECK_MSG("NUMP"); printf("LISTGAME< NUMP\n"); /* send num players */ i = htonl(numplayer); send_msg(mysock, &i, 4); printf("LISTGAME> %d\n", numplayer); /* read number of games */ read_msg(mysock, &numgames, 4, &len); numgames = ntohl(numgames); printf("LISTGAME< %d (numgames)\n", numgames); for (i = 0; i < numgames; i++) { int id = 0; Game *game = malloc(sizeof(Game)); memset(game, 0, sizeof(Game)); read_msg(mysock, &id, 4, &len); game->id = ntohl(id); printf("LISTGAME< %d (id)\n", game->id); read_msg(mysock, buf, 255, &len); buf[254] = '\0'; game->name = strdup(buf); printf("LISTGAME< %s (name)\n", game->name); game->num_players = numplayer; games = llist_append(games, game); } return games; err_protocol: close(mysock); err_socket: mysock = INVSOCK; return NULL; } void net_get_info(Game *game) { int gameid = htonl(game->id); char buf[255]; unsigned char len; int tmp, i; printf("PRELJOIN: sock %d\n", mysock); #ifndef __MINGW32__ assert(mysock > 0); #else assert(mysock != INVALID_SOCKET); #endif send_msg(mysock, "PRELJOIN", strlen("PRELJOIN") + 1); printf("PRELJOIN> PRELJOIN\n"); send_msg(mysock, &gameid, 4); printf("PRELJOIN> %d (id)\n", game->id); memset(buf, 0, 255); read_msg(mysock, buf, 255, &len); buf[254] = '\0'; printf("PRELJOIN< %s (answer)\n", buf); if (!strncmp(buf, "ERROR1", 6)) { close(mysock); mysock = INVSOCK; return; } for (i = 0; i < game->num_players; i++) { read_msg(mysock, buf, 255, &len); buf[254] = '\0'; printf("PRELJOIN< %s (player name)\n", buf); game->player_name[i] = strdup(buf); game->player_type[i] = INPUT_NETWORK; } read_msg(mysock, &tmp, 4, &len); tmp = ntohl(tmp); printf("PRELJOIN< %d (first avail spot)\n", tmp); game->first_avail_spot = tmp; } void net_join(int id, int nump, char *my_player_name) { char buf[255]; unsigned char len; int mid = htonl(nump); printf("JOIN: sock %d\n", mysock); #ifndef __MINGW32__ assert(mysock > 0); #else assert(mysock != INVALID_SOCKET); #endif send_msg(mysock, "JOIN", strlen("JOIN") + 1); printf("JOIN> JOIN\n"); send_msg(mysock, &mid, 4); printf("JOIN> %d (num player)\n", nump); read_msg(mysock, buf, 255, &len); buf[254] = '\0'; printf("JOIN< %s (answer)\n", buf); if (strncmp(buf, "OK", 2)) { close(mysock); mysock = INVSOCK; return; } send_msg(mysock, my_player_name, strlen(my_player_name) + 1); printf("JOIN> %s (my name)\n", my_player_name); } void net_send_event(int player, int x, int y) { char cmd = 'p'; int tmp; #ifndef __MINGW32__ if (mysock < 0) return; #else if(mysock == INVALID_SOCKET) return; #endif send_msg(mysock, &cmd, 1); tmp = htonl(player); send_msg(mysock, &tmp, 4); tmp = htonl(x); send_msg(mysock, &tmp, 4); tmp = htonl(y); send_msg(mysock, &tmp, 4); } static SDL_Thread *screen_thread = NULL; static int run_screen_thread = FALSE; static int screen_repaint(void *data) { while (run_screen_thread) { SDL_UpdateRect(screen, 0, 0, 0, 0); SDL_Delay(1000); } return 0; } void net_get_event(int player, int *x, int *y) { char cmd = 'r'; int tmp, tmp_x, tmp_y; unsigned char len; #ifndef __MINGW32__ if (mysock < 0) return; #else if(mysock == INVALID_SOCKET) return; #endif run_screen_thread = TRUE; screen_thread = SDL_CreateThread(screen_repaint, NULL); send_msg(mysock, &cmd, 1); tmp = htonl(player); if (send_msg(mysock, &tmp, 4) < 0 || read_msg(mysock, &tmp_x, 4, &len) < 0 || read_msg(mysock, &tmp_y, 4, &len) < 0) { printf("can't get event\n"); *x = -2; *y = -2; } else { tmp_x = ntohl(tmp_x); tmp_y = ntohl(tmp_y); *x = tmp_x; *y = tmp_y; } run_screen_thread = FALSE; SDL_WaitThread(screen_thread, &tmp); } void net_end_game(int player) { char cmd = 'q'; int tmp; #ifndef __MINGW32__ if (mysock < 0) return; #else if(mysock == INVALID_SOCKET) return; #endif send_msg(mysock, &cmd, 1); tmp = htonl(player); send_msg(mysock, &tmp, 4); } void net_close(void) { #ifndef __MINGW32__ if (mysock < 0) return; #else if(mysock == INVALID_SOCKET) return; #endif close(mysock); mysock = INVSOCK; } static char *server = NULL; const char *net_get_server(void) { return server ? server:NET_HOST; } void net_set_server(const char *srv) { if (server) free(server); server = srv ? strdup(srv):NULL ; }