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