1 /** EMULib Emulation Library *********************************/
2 /**                                                         **/
3 /**                         NetUnix.c                       **/
4 /**                                                         **/
5 /** This file contains standard communication routines for  **/
6 /** Unix using TCP/IP via sockets.                          **/
7 /**                                                         **/
8 /** Copyright (C) Marat Fayzullin 1997-2009                 **/
9 /**     You are not allowed to distribute this software     **/
10 /**     commercially. Please, notify me, if you make any    **/
11 /**     changes to this file.                               **/
12 /*************************************************************/
13 #include "EMULib.h"
14 #include "NetPlay.h"
15 
16 #include <string.h>
17 #include <unistd.h>
18 #include <stdio.h>
19 #include <netdb.h>
20 #include <errno.h>
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 
25 static int IsServer = 0;
26 static int Socket   = -1;
27 static int Blocking = 1;
28 
29 /** NETConnected() *******************************************/
30 /** Returns NET_SERVER, NET_CLIENT, or NET_OFF.             **/
31 /*************************************************************/
NETConnected(void)32 int NETConnected(void)
33 { return(Socket<0? NET_OFF:IsServer? NET_SERVER:NET_CLIENT); }
34 
35 /** NETMyName() **********************************************/
36 /** Returns local hostname/address or 0 on failure.         **/
37 /*************************************************************/
NETMyName(char * Buffer,int MaxChars)38 const char *NETMyName(char *Buffer,int MaxChars)
39 {
40   struct hostent *Host;
41 
42   /* Have to have enough characters */
43   if(MaxChars<16) return(0);
44   /* Get local hostname */
45   gethostname(Buffer,MaxChars);
46   /* Look up address */
47   if(!(Host=gethostbyname(Buffer))) return(0);
48   /* Must have an address */
49   if(!Host->h_addr_list||!Host->h_addr_list[0]) return(0);
50   /* Copy address */
51   sprintf(Buffer,"%d.%d.%d.%d",
52     Host->h_addr_list[0][0],
53     Host->h_addr_list[0][1],
54     Host->h_addr_list[0][2],
55     Host->h_addr_list[0][3]
56   );
57   return(Buffer);
58 }
59 
60 /** NETConnect() *********************************************/
61 /** Connects to Server:Port. When Host=0, becomes a server, **/
62 /** waits at for an incoming request, and connects. Returns **/
63 /** the NetPlay connection status, like NETConnected().     **/
64 /*************************************************************/
NETConnect(const char * Server,unsigned short Port)65 int NETConnect(const char *Server,unsigned short Port)
66 {
67   struct sockaddr_in Addr;
68   struct hostent *Host;
69   int AddrLength,LSocket;
70   unsigned long J;
71 
72   /* Close existing network connection */
73   NETClose();
74 
75   /* Clear the address structure */
76   memset(&Addr,0,sizeof(Addr));
77 
78   /* If the server name is given, we first try to */
79   /* connect as a client.                         */
80   if(Server)
81   {
82     /* Look up server address */
83     if(!(Host=gethostbyname(Server))) return(NET_OFF);
84 
85     /* Set fields of the address structure */
86     memcpy(&Addr.sin_addr,Host->h_addr,Host->h_length);
87     Addr.sin_family = AF_INET;
88     Addr.sin_port   = htons(Port);
89 
90     /* Create a socket */
91     if((Socket=socket(AF_INET,SOCK_STREAM,0))<0) return(NET_OFF);
92 
93     /* Connecting... */
94     if(connect(Socket,(struct sockaddr *)&Addr,sizeof(Addr))>=0)
95     {
96       /* Make communication socket blocking/non-blocking */
97       J=!Blocking;
98       if(ioctl(Socket,FIONBIO,&J)<0)
99       { close(Socket);Socket=-1;return(NET_OFF); }
100       /* Succesfully connected as client */
101       IsServer=0;
102       return(NET_CLIENT);
103     }
104 
105     /* Failed to connect as a client */
106     close(Socket);
107   }
108 
109   /* Connection as client either failed or hasn't */
110   /* been attempted at all. Becoming a server and */
111   /* waiting for connection request.              */
112 
113   /* Set fields of the address structure */
114   Addr.sin_addr.s_addr = htonl(INADDR_ANY);
115   Addr.sin_family      = AF_INET;
116   Addr.sin_port        = htons(Port);
117 
118   /* Create a listening socket */
119   if((LSocket=socket(AF_INET,SOCK_STREAM,0))<0) return(NET_OFF);
120 
121   /* Bind listening socket */
122   if(bind(LSocket,(struct sockaddr *)&Addr,sizeof(Addr))<0)
123   { close(LSocket);return(NET_OFF); }
124 
125   /* Make listening socket non-blocking */
126   J=1;
127   if(ioctl(LSocket,FIONBIO,&J)<0)
128   { close(LSocket);return(NET_OFF); }
129 
130   /* Listen for one client */
131   if(listen(LSocket,1)<0)
132   { close(LSocket);return(NET_OFF); }
133 
134   /* Accepting calls... */
135   AddrLength=sizeof(Addr);
136   GetKey();
137   do
138   {
139 #ifdef MAEMO
140     GTKProcessEvents();
141 #else
142     X11ProcessEvents();
143 #endif
144     Socket=accept(LSocket,(struct sockaddr *)&Addr,&AddrLength);
145     if(Socket==EWOULDBLOCK) break;
146   }
147   while((Socket<0)&&VideoImg&&!GetKey());
148   close(LSocket);
149 
150   /* Client failed to connect */
151   if(Socket<0) return(NET_OFF);
152 
153   /* Make communication socket blocking/non-blocking */
154   J=!Blocking;
155   if(ioctl(Socket,FIONBIO,&J)<0)
156   { close(Socket);Socket=-1;return(NET_OFF); }
157 
158   /* Client connected succesfully */
159   IsServer=1;
160   return(NET_SERVER);
161 }
162 
163 /** NETClose() ***********************************************/
164 /** Closes connection open with NETConnect().               **/
165 /*************************************************************/
NETClose(void)166 void NETClose(void)
167 {
168   if(Socket>=0) close(Socket);
169   Socket   = -1;
170   IsServer = 0;
171 }
172 
173 /** NETBlock() ***********************************************/
174 /** Makes NETSend()/NETRecv() blocking or not blocking.     **/
175 /*************************************************************/
NETBlock(int Switch)176 int NETBlock(int Switch)
177 {
178   unsigned long J;
179 
180   /* Toggle blocking if requested */
181   if(Switch==NET_TOGGLE) Switch=!Blocking;
182 
183   /* If switching blocking... */
184   if((Switch==NET_OFF)||(Switch==NET_ON))
185   {
186     J=!Switch;
187     if((Socket<0)||(ioctl(Socket,FIONBIO,&J)>=0)) Blocking=Switch;
188   }
189 
190   /* Return blocking state */
191   return(Blocking);
192 }
193 
194 /** NETSend() ************************************************/
195 /** Send N bytes. Returns number of bytes sent or 0.        **/
196 /*************************************************************/
NETSend(const char * Out,int N)197 int NETSend(const char *Out,int N)
198 {
199   int J,I;
200 
201   /* Have to have a socket */
202   if(Socket<0) return(0);
203 
204   /* Send data */
205   for(I=J=N;(J>=0)&&I;)
206   {
207     J=send(Socket,Out,I,0);
208     if(J>0) { Out+=J;I-=J; }
209   }
210 
211   /* Return number of bytes sent */
212   return(N-I);
213 }
214 
215 /** NETRecv() ************************************************/
216 /** Receive N bytes. Returns number of bytes received or 0. **/
217 /*************************************************************/
NETRecv(char * In,int N)218 int NETRecv(char *In,int N)
219 {
220   int J,I;
221 
222   /* Have to have a socket */
223   if(Socket<0) return(0);
224 
225   /* Receive data */
226   for(I=J=N;(J>=0)&&I;)
227   {
228     J=recv(Socket,In,I,0);
229     if(J>0) { In+=J;I-=J; }
230   }
231 
232   /* Return number of bytes received */
233   return(N-I);
234 }
235