//Copyright (C) 2007 Ryan Houdek////This library is free software; you can redistribute it and/or//modify it under the terms of the GNU Lesser General Public//License as published by the Free Software Foundation; either//version 2.1 of the License, or (at your option) any later version.////This library 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//Lesser General Public License for more details.////You should have received a copy of the GNU Lesser General Public//License along with this library; if not, write to the Free Software//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA#include <string.h>#include <stdarg.h>#include <stdlib.h>#ifndef WIN32#include <unistd.h>#endif#include <SDL/SDL.h>#include <SDL/SDL_net.h>#include "tcputil.h"unsigned char *Server;long ServerSize=0;char *mformat(char *format,...){ va_list ap; Uint32 len=0; static char *str=NULL; char *p, *s; char c; int d; unsigned int u; if(str) { free(str); str=NULL; } if(!format) return(NULL); va_start(ap,format); for(p=format; *p; p++) { switch(*p) { case 's': // string s=va_arg(ap, char*); str=(char*)realloc(str,((len+strlen(s)+4)/4)*4); sprintf(str+len,"%s",s); break; case 'c': // char c=(char)va_arg(ap, int); str=(char*)realloc(str,len+4); sprintf(str+len,"%c",c); break; case 'd': // int d=va_arg(ap, int); str=(char*)realloc(str,((len+64)/4)*4); sprintf(str+len,"%d",d); break; case 'u': // unsigned int u=va_arg(ap, unsigned int); str=(char*)realloc(str,((len+64)/4)*4); sprintf(str+len,"%u",u); break; } // set len to the new string length if(str) len=strlen(str); else len=0; } va_end(ap); return(str);}typedef struct { TCPsocket sock; char *name; void StartClient(); void EndClient(); float x; float y; float vely; float velx; float angle; char jstate; int dir; int tmp[32]; int id;} Client;int idnum=0;void Client::StartClient(){ jstate = 0; vely = 0.0f; velx = 0.0f; angle = 0.0f; x = 50.0f; y = 50.0f; id=idnum; idnum++; putMsg(sock,mformat("ssd","ID"," ",id)); printf("hmmm\n");}void Client::EndClient(){}int running=1;Client *clients=NULL;int num_clients=0;TCPsocket server;#ifdef WIN32#define strcasecmp _stricmp#define strncasecmp _strnicmpchar *strsep(char **stringp, const char *delim){ char *p; if(!stringp) return(NULL); p=*stringp; while(**stringp && !strchr(delim,**stringp)) (*stringp)++; if(**stringp) { **stringp='\0'; (*stringp)++; } else *stringp=NULL; return(p);}#endifvoid send_all(char *buf);int find_client_name(char *name);// this is a simplistic printf-like function the format only takes a string of// chars that represent datatypes.// it mallocs space and prints into that buffer.// it uses a static pointer so that the user doesn't have to free the buffer// terminate the nick at "bad" characters...void fix_nick(char *s){ unsigned int i; if((i=strspn(s,"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ|_=+.,:;/\\?!@#$%^&*()~`"))!=strlen(s)) s[i]='\0';}// test for nice name uniqueness among already connected usersint unique_nick(char *s){ return(find_client_name(s)==-1);}// add a client into our array of clientsClient *add_client(TCPsocket sock, char *name){ fix_nick(name); if(!strlen(name)) { putMsg(sock,"Invalid Nickname...bye bye!"); SDLNet_TCP_Close(sock); return(NULL); } if(!unique_nick(name)) { putMsg(sock,"Duplicate Nickname...bye bye!"); SDLNet_TCP_Close(sock); return(NULL); } clients=(Client*)realloc(clients, (num_clients+1)*sizeof(Client)); clients[num_clients].name=name; clients[num_clients].sock=sock; num_clients++; // server side info printf("--> %s\n",name); // inform all clients, including the new one, of the joined user send_all(mformat("ss","--> ",name)); return(&clients[num_clients-1]);}// find a client in our array of clients by it's socket.// the socket is always uniqueint find_client(TCPsocket sock){ int i; for(i=0;i<num_clients;i++) if(clients[i].sock==sock) return(i); return(-1);}// find a client in our array of clients by it's socket.// the name is always uniqueint find_client_name(char *name){ int i; for(i=0;i<num_clients;i++) if(!strcasecmp(clients[i].name,name)) return(i); return(-1);}// remove a client from our array of clientsvoid remove_client(int i){ char *name=clients[i].name; int client_id = clients[i].id; if(i<0 && i>=num_clients) return; // close the old socket, even if it's dead... SDLNet_TCP_Close(clients[i].sock); num_clients--; if(num_clients>i) memmove(&clients[i], &clients[i+1], (num_clients-i)*sizeof(Client)); clients=(Client*)realloc(clients, num_clients*sizeof(Client)); // server side info printf("<-- %s\n",name); // inform all clients, excluding the old one, of the disconnected user send_all(mformat("ssd","QUIT"," ",client_id)); if(name) free(name);}// create a socket set that has the server socket and all the client socketsSDLNet_SocketSet create_sockset(){ static SDLNet_SocketSet set=NULL; int i; if(set) SDLNet_FreeSocketSet(set); set=SDLNet_AllocSocketSet(num_clients+1); if(!set) { printf("SDLNet_AllocSocketSet: %s\n", SDLNet_GetError()); exit(1); //most of the time this is a major error, but do what you want. } SDLNet_TCP_AddSocket(set,server); for(i=0;i<num_clients;i++) SDLNet_TCP_AddSocket(set,clients[i].sock); return(set);}// send a buffer to all clientsvoid send_all(char *buf){ int cindex; if(!buf || !num_clients) return; cindex=0; while(cindex<num_clients) { // putMsg is in tcputil.h, it sends a buffer over a socket // with error checking if(putMsg(clients[cindex].sock,buf)) cindex++; else remove_client(cindex); }}void do_command(char *msg, Client *client){ char *command,*p; int len; if(!msg || !strlen(msg) || !client) return; len=strlen(msg); p=msg; command=strsep(&p," \t"); // /NICK : change the clients name if(!strcasecmp(command,"NICK")) { if(p && strlen(p)) { char *old_name=client->name; fix_nick(p); if(!strlen(p)) { putMsg(client->sock,"--- Invalid Nickname!"); return; } if(!unique_nick(p)) { putMsg(client->sock,"--- Duplicate Nickname!"); return; } client->name=strdup(p); send_all(mformat("ssss","--- ",old_name," --> ",p)); free(old_name); } else putMsg(client->sock,"--- /NICK nickname"); return; } if(!strcasecmp(command,"GET")) { char tmp[256]; sprintf(tmp, "SIZE %i", ServerSize); putMsg(client->sock, tmp); client->dir = 0; return; } if(!strcasecmp(command,"START")) { if(client->dir == 0) putMsg(client->sock, "START"); if(client->dir > ServerSize) { putMsg(client->sock,"STOP"); return; } char tmp[16]; sprintf(tmp,"%d",Server[client->dir]); //printf("%c",Server[client->dir]); putMsg(client->sock,tmp); client->dir++; return; }}#undef mainint main(int argc, char **argv){ IPaddress ip; TCPsocket sock; SDLNet_SocketSet set; char *message=NULL,*host; Uint32 ipaddr; Uint16 port; // initialize SDL if(SDL_Init(0)==-1) { printf("SDL_Init: %s\n",SDL_GetError()); exit(1); } // initialize SDL_net if(SDLNet_Init()==-1) { printf("SDLNet_Init: %s\n",SDLNet_GetError()); SDL_Quit(); exit(2); } // get the port from the commandline port=5505; // Resolve the argument into an IPaddress type if(SDLNet_ResolveHost(&ip,NULL,port)==-1) { printf("SDLNet_ResolveHost: %s\n",SDLNet_GetError()); SDLNet_Quit(); SDL_Quit(); exit(3); } // perform a byte endianess correction for the next printf ipaddr=SDL_SwapBE32(ip.host); // output the IP address nicely printf("IP Address : %d.%d.%d.%d\n", ipaddr>>24, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff); // resolve the hostname for the IPaddress host=(char*)SDLNet_ResolveIP(&ip); // print out the hostname we got if(host) printf("Hostname : %s\n",host); else printf("Hostname : N/A\n"); // output the port number printf("Port : %d\n",port); // open the server socket server=SDLNet_TCP_Open(&ip); if(!server) { printf("SDLNet_TCP_Open: %s\n",SDLNet_GetError()); SDLNet_Quit(); SDL_Quit(); exit(4); } FILE * pFile; long size; pFile = fopen ("Game","rb"); if (pFile==NULL) perror ("Error opening file"); else { fseek (pFile, 0, SEEK_END); size=ftell (pFile); ServerSize = size; rewind(pFile); Server = (unsigned char*)malloc(size); long result = fread ( Server, 1, size, pFile ); if (result != size) {fputs ("Reading error",stderr); exit (3);} fclose (pFile); printf ("Size of myfile.txt: %ld bytes.\n",size); } while(1) { int numready,i; set=create_sockset(); numready=SDLNet_CheckSockets(set, (Uint32)-1); if(numready==-1) { printf("SDLNet_CheckSockets: %s\n",SDLNet_GetError()); break; } if(!numready) continue; if(SDLNet_SocketReady(server)) { numready--; //printf("Connection...\n"); sock=SDLNet_TCP_Accept(server); if(sock) { char *name=NULL; //printf("Accepted...\n"); if(getMsg(sock, &name)) { Client *client; client=add_client(sock,name); if(client) { client->StartClient(); do_command("WHO",client); } } else SDLNet_TCP_Close(sock); } } for(i=0; numready && i<num_clients; i++) { if(SDLNet_SocketReady(clients[i].sock)) { if(getMsg(clients[i].sock, &message)) { char *str; numready--; //printf("<%s> %s\n",clients[i].name,message); // interpret commands if(message[0]=='/' && strlen(message)>1) { do_command(message+1,&clients[i]); } else // it's a regular message { // forward message to ALL clients... str=mformat("ssss","<",clients[i].name,"> ",message); if(str) send_all(str); } free(message); message=NULL; } else remove_client(i); } } } // shutdown SDL_net SDLNet_Quit(); // shutdown SDL SDL_Quit(); return(0);}