/* * file com_to_client.c - handle communications with clients * * $Id: com_to_client.c,v 1.3 2004/05/14 10:00:33 alfie Exp $ * * Program XBLAST * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net) * * 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; or (at your option) * any later version * * This program is distributed in the hope that it will be entertaining, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILTY 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 */ #include "com_to_client.h" #include "com_stream.h" #include "net_tele.h" #include "server.h" #include "cfg_level.h" /* * local types */ typedef struct { XBCommStream stream; unsigned serial; } XBCommToClient; /* * local variables */ static XBCommToClient *commList[MAX_HOSTS] = { /* this entry is never used (server) */ NULL, /* up to 5 clients can connect */ NULL, NULL, NULL, NULL, NULL, }; /* * */ static XBCommResult HandleDataAvailable (XBCommToClient *toClient, const XBTelegram *tele) { const void *data; size_t len; assert (toClient != NULL); /* get telegramm data */ data = Net_TeleData (tele, &len); switch (Net_TeleID (tele)) { case XBT_ID_GameConfig: Server_ReceiveGameConfig (toClient->serial, data); break; case XBT_ID_PlayerConfig: Server_ReceivePlayerConfig (toClient->serial, (int) Net_TeleIOB (tele), data); break; default: break; } return XCR_OK; } /* HandleDataAvailable */ /* * */ static XBCommResult HandleDataNotAvailable (XBCommToClient *toClient, const XBTelegram *tele) { switch (Net_TeleID (tele)) { case XBT_ID_GameConfig: break; default: break; } return XCR_OK; } /* HandleDataAvailable */ /* * */ static XBCommResult HandleActivate (XBCommToClient *toClient, const XBTelegram *tele) { const void *data; size_t len; unsigned value; assert (toClient != NULL); /* get telegramm data */ data = Net_TeleData (tele, &len); switch (Net_TeleID (tele)) { case XBT_ID_DgramPort: /* inform application */ if (NULL != data && 1 == sscanf (data, "%u", &value) ) { Server_ReceiveDgramPort (toClient->serial, value); } return XCR_OK; default: return XCR_OK; } } /* HandleActivate */ /* * */ static XBCommResult HandleSpontaneous (XBCommToClient *toClient, const XBTelegram *tele) { assert (toClient != NULL); /* get telegramm data */ switch (Net_TeleID (tele)) { case XBT_ID_Sync: Server_ReceiveSync (toClient->serial, Net_TeleIOB (tele) ); return XCR_OK; default: return XCR_OK; } } /* HandleSpontaneous */ /* * handle telegrams from server */ static XBCommResult HandleTelegram (XBCommStream *stream, const XBTelegram *tele) { XBCommToClient *toClient = (XBCommToClient *) stream; assert (toClient != NULL); switch (Net_TeleCOT (tele)) { /* client sends requested data */ case XBT_COT_DataAvailable: return HandleDataAvailable (toClient, tele); /* client has not requested data */ case XBT_COT_DataNotAvailable: return HandleDataNotAvailable (toClient, tele); /* client command has arrived */ case XBT_COT_Activate: return HandleActivate (toClient, tele); /* client message has arrived */ case XBT_COT_Spontaneous: return HandleSpontaneous (toClient, tele); default: return XCR_Error; } } /* HandleTelegram */ /* * */ static XBCommResult DeleteToClient (XBComm *comm) { XBCommToClient *toClient = (XBCommToClient *) comm; assert (comm != NULL); assert (toClient == commList[toClient->serial]); /* unmark client */ commList[toClient->serial] = NULL; /* clean up */ Stream_CommFinish (&toClient->stream); /* make sure datagramm connection is also cancelled and application is informed */ Server_ReceiveDisconnect (toClient->serial); /* free memory */ free (comm); return XCR_OK; } /* DeleteToClient */ /* * */ static void ErrorToClient (XBCommStream *comm) { XBCommToClient *toClient = (XBCommToClient *) comm; assert (toClient != NULL); Server_NotifyError (toClient->serial); } /* ErrorToClient */ /* * create listeneing communication */ XBComm * S2C_CreateComm (const XBSocket *socket) { unsigned serial; XBSocket *pSocket; XBCommToClient *toClient; assert (socket != NULL); /* get free serial */ for (serial = 1; serial < MAX_HOSTS; serial ++) { if (NULL == commList[serial]) { break; } } if (serial >= MAX_HOSTS) { return NULL; } /* create listen socket */ pSocket = Net_Accept (socket); if (NULL == pSocket) { return NULL; } /* create communication data structure */ toClient = calloc (1, sizeof (XBCommToClient) ); assert (NULL != toClient); /* set values */ Stream_CommInit (&toClient->stream, COMM_ToClient, pSocket, HandleTelegram, ErrorToClient, DeleteToClient); toClient->serial = serial; /* add to inernal list */ commList[serial] = toClient; /* inform application */ Server_Accept (serial, Net_RemoteName (pSocket), Net_RemotePort (pSocket)); /* that's all */ return &toClient->stream.comm; } /* S2C_CreateComm */ /* * check if client is connected */ XBBool S2C_Connected (unsigned id) { assert (id > 0); assert (id < MAX_HOSTS); return (commList[id] != NULL); } /* S2C_Connected */ /* * send game config to client */ void S2C_SendGameConfig (unsigned id, unsigned hostID, XBAtom atom) { assert (id > 0); assert (id <= MAX_HOSTS); assert (commList[id] != NULL); assert (commList[id]->stream.sndQueue != NULL); /* send database section */ Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); SendGameConfig (CT_Remote, commList[id]->stream.sndQueue, XBT_COT_SendData, (XBTeleIOB) hostID, atom); } /* S2C_SendGameConfig */ /* * query game config from client */ void S2C_QueryGameConfig (unsigned id) { assert (id > 0); assert (id < MAX_HOSTS); assert (commList[id] != NULL); assert (commList[id]->stream.sndQueue != NULL); /* send request */ Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_RequestData, XBT_ID_GameConfig, 0, NULL, 0) ); } /* S2C_QueryGameConfig */ /* * query player config from client */ void S2C_QueryPlayerConfig (unsigned id, int player) { assert (id > 0); assert (id < MAX_HOSTS); assert (commList[id] != NULL); assert (commList[id]->stream.sndQueue != NULL); assert (player < NUM_LOCAL_PLAYER); /* send request */ Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_RequestData, XBT_ID_PlayerConfig, (XBTeleIOB) player, NULL, 0) ); } /* S2C_QueryPlayerConfig */ /* * send game config to client */ void S2C_SendPlayerConfig (unsigned id, unsigned hostId, int player, XBAtom atom) { XBTeleIOB iob; assert (id > 0); assert (id < MAX_HOSTS); assert (commList[id] != NULL); assert (commList[id]->stream.sndQueue != NULL); /* convert id and player ti iob */ iob = ((XBTeleIOB) hostId << 4) + (XBTeleIOB) player; /* send database section */ Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); SendPlayerConfig (CT_Remote, commList[id]->stream.sndQueue, XBT_COT_SendData, iob, atom, XBFalse); // XBCC not to central } /* S2C_SendPlayerConfig */ /* * send disconnect message to client */ void S2C_HostDisconnected (unsigned id, unsigned hostID) { assert (id > 0); assert (id < MAX_HOSTS); assert (commList[id] != NULL); Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Spontaneous, XBT_ID_HostDisconnected, hostID, NULL, 0) ); } /* S2C_HostDisconnected */ /* * send request for disconnect to given client */ void S2C_Disconnect (unsigned id) { assert (id > 0); assert (id < MAX_HOSTS); assert (commList[id] != NULL); /* inform host about disconnect request */ Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Spontaneous, XBT_ID_HostDisconnected, 0, NULL, 0) ); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_RequestDisconnect, 0, NULL, 0) ); } /* S2C_Disconnect */ /* * send random seed to client */ void S2C_SendDgramPort (unsigned id, unsigned short port) { char tmp[16]; /* sanity check */ assert (id > 0); assert (id <= MAX_HOSTS); assert (commList[id] != NULL); assert (commList[id]->stream.sndQueue != NULL); /* send seed as ascii */ sprintf (tmp, "%hu", port); /* send data */ Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_DgramPort, id, tmp, strlen (tmp) + 1) ); } /* S2C_SendDgramPort */ /* * start game signal to client */ void S2C_StartGame (unsigned id) { assert (id > 0); assert (id < MAX_HOSTS); assert (commList[id] != NULL); Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_StartGame, (XBTeleIOB) id, NULL, 0) ); } /* S2C_StartGame */ /* * send random seed to client */ void S2C_SendRandomSeed (unsigned id, unsigned seed) { char tmp[16]; /* sanity check */ assert (id > 0); assert (id <= MAX_HOSTS); assert (commList[id] != NULL); assert (commList[id]->stream.sndQueue != NULL); /* send seed as ascii */ sprintf (tmp, "%u", seed); /* send data */ Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_RandomSeed, 0, tmp, strlen (tmp) + 1) ); } /* S2C_SendRandomSeed */ /* * send level data to client */ void S2C_SendLevelConfig (unsigned id, const DBRoot *level) { assert (id > 0); assert (id <= MAX_HOSTS); assert (commList[id] != NULL); assert (commList[id]->stream.sndQueue != NULL); /* send database section */ Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); SendLevelConfig (commList[id]->stream.sndQueue, XBT_COT_SendData, level); } /* S2C_SendGameConfig */ /* * hostname of client */ const char * S2C_HostName (unsigned id) { assert (id > 0); assert (id <= MAX_HOSTS); assert (commList[id] != NULL); /* get name from socket */ return Net_RemoteName (commList[id]->stream.comm.socket); } /* S2C_HostName */ /* * hostname of client */ const char * S2C_LocalName (unsigned id) { assert (id > 0); assert (id <= MAX_HOSTS); assert (commList[id] != NULL); /* get name from socket */ return Net_LocalName (commList[id]->stream.comm.socket); } /* S2C_LocalName */ /* * start game signal to client */ void S2C_Sync (unsigned id, XBNetworkEvent event) { assert (id > 0); assert (id < MAX_HOSTS); assert (commList[id] != NULL); Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_Sync, (XBTeleIOB) event, NULL, 0) ); } /* S2C_Sync */ /* * send host state to clients */ void S2C_SendHostState (unsigned id, unsigned hostID, XBBool isIn) { assert (id > 0); assert (id < MAX_HOSTS); assert (commList[id] != NULL); Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); if (isIn) { Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_HostIsIn, (XBTeleIOB) hostID, NULL, 0) ); } else { Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_HostIsOut, (XBTeleIOB) hostID, NULL, 0) ); } } /* S2C_SendHostState */ /* * send team state to clients */ void S2C_SendTeamState (unsigned id, unsigned hostID, unsigned team) { char tmp[16]; assert (id > 0); assert (id < MAX_HOSTS); assert (commList[id] != NULL); sprintf (tmp, "%hu", team); Socket_RegisterWrite (CommSocket (&commList[id]->stream.comm)); Net_SendTelegram (commList[id]->stream.sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_TeamChange, (XBTeleIOB) hostID, tmp, strlen (tmp) + 1) ); } /* S2C_SendHostState */ /* * end of file com_to_client.c */