1 /*
2 * Alizarin Tetris
3 * Low level networking routines.
4 *
5 * Copyright 2000, Kiri Wagstaff & Westley Weimer
6 */
7
8 #include <config.h> /* go autoconf! */
9 #include "atris.h"
10
11 #include <sys/types.h>
12 #include <unistd.h>
13
14 #if HAVE_NETDB_H
15 #include <fcntl.h>
16 #endif
17
18 #if HAVE_NETINET_IN_H
19 #include <netinet/in.h>
20 #endif
21
22 #if HAVE_NETDB_H
23 #include <netdb.h>
24 #endif
25
26 #include <time.h>
27
28 #if HAVE_SYS_SOCKET_H
29 #include <sys/socket.h>
30 #else
31 #if HAVE_WINSOCK_H
32 #include <winsock.h>
33 #endif
34 #endif
35
36 char *error_msg = NULL;
37
38 /***************************************************************************
39 * Server_AwaitConnection()
40 * Sets up the server side listening socket and awaits connections from the
41 * outside world. Returns a socket.
42 *********************************************************************PROTO*/
43 int
Server_AwaitConnection(int port)44 Server_AwaitConnection(int port)
45 {
46 static struct sockaddr_in addr;
47 static struct hostent *host;
48 static int sockListen=0;
49 static int addrLen;
50 int val1;
51 struct linger val2;
52 int sock;
53
54 if (sockListen == 0) {
55 memset(&addr,0,sizeof(addr));
56 addr.sin_family=AF_INET;
57 addr.sin_addr.s_addr=htonl(INADDR_ANY);
58 addr.sin_port=htons(port);
59 sockListen=socket(AF_INET,SOCK_STREAM,0);
60
61 error_msg = 0;
62
63 if (sockListen < 0) {
64 Debug("unable to create socket: %s\n",error_msg = strerror(errno));
65 return -1;
66 }
67
68 val1=1;
69
70 #ifdef HAVE_SYS_SOCKET_H
71 if (fcntl(sockListen, F_SETFL, O_NONBLOCK)) {
72 Debug("unable to make socket non-blocking: %s\n", error_msg = strerror(errno));
73 return -1;
74 }
75 #endif
76
77 if (setsockopt(sockListen,SOL_SOCKET,SO_REUSEADDR,
78 (void *)&val1, sizeof(val1))) {
79 Debug("WARNING: setsockopt(...,SO_REUSEADDR) failed. You may have to wait a\n"
80 "\tfew minutes before you can try to be the server again.\n");
81 }
82 if (bind(sockListen, (struct sockaddr *)&addr, sizeof(addr))) {
83 Debug("unable to bind socket (for listening): %s\n", error_msg = strerror(errno));
84 return -1;
85 }
86 if (listen(sockListen,16)) {
87 Debug("unable to listen on socket: %s\n", error_msg = strerror(errno));
88 return -1;
89 }
90
91 addrLen=sizeof(addr);
92
93 Debug("accepting connections on port %d, socketfd %d\n",port,sockListen);
94 }
95 #if HAVE_SELECT || HAVE_WINSOCK_H
96 /* it is possible to select() on a socket for the purpose of doing an
97 * accept by putting it in the read group */
98 {
99 fd_set read_fds;
100 struct timeval timeout = {0, 0};
101 int retval;
102
103 FD_ZERO(&read_fds);
104 FD_SET(sockListen, &read_fds);
105
106 retval = select(sockListen+1, &read_fds, NULL, NULL, &timeout);
107
108 if (retval <= 0) {
109 /* no one is there */
110 return -1;
111 }
112 }
113 #endif
114 sock=accept(sockListen, (struct sockaddr *)&addr,&addrLen);
115 if (sock < 0) {
116 if (
117 #ifdef HAVE_SYS_SOCKET_H
118 errno == EWOULDBLOCK ||
119 #endif
120 errno == EAGAIN)
121 return -1;
122 else {
123 Debug("unable to accept on listening socket: %s\n", error_msg = strerror(errno));
124 return -1;
125 }
126 }
127
128 val2.l_onoff=0; val2.l_linger=0;
129 if (setsockopt(sock,SOL_SOCKET,SO_LINGER,(void *)&val2,sizeof(val2)))
130 Debug("WARNING: setsockopt(...,SO_LINGER) failed. You may have to wait a few\n"
131 "\tminutes before you can try to be the server again.\n");
132
133 host=gethostbyaddr((void *)&addr.sin_addr,sizeof(struct in_addr),AF_INET);
134 if (!host)
135 Debug("connection from some unresolvable IP address, socketfd %d.\n", sock);
136 else
137 Debug("connection from %s, socketfd %d.\n",host->h_name,sock);
138 return sock;
139 }
140
141 /***************************************************************************
142 * Client_Connect()
143 * Set up client side networking and connect to the server. Returns a socket
144 * pointing to the server.
145 *
146 * On error, -1 is returned.
147 *********************************************************************PROTO*/
148 int
Client_Connect(char * hoststr,int lport)149 Client_Connect(char *hoststr, int lport)
150 {
151 struct sockaddr_in addr;
152 struct hostent *host;
153 int mySock;
154 short port = lport;
155 int retval;
156
157 error_msg = NULL;
158
159 host=gethostbyname(hoststr);
160 if (!host) {
161 Debug("unable to resolve [%s]: unknown hostname\n",hoststr);
162 error_msg = "unknown hostname";
163 return -1;
164 }
165
166 Debug("connecting to %s:%d ...\n",host->h_name,port);
167
168 memset(&addr, 0, sizeof(addr));
169 addr.sin_family = AF_INET; /*host->h_addrtype;*/
170 memcpy(&addr.sin_addr, host->h_addr, host->h_length);
171 addr.sin_port=htons(port);
172 mySock = socket(AF_INET, SOCK_STREAM, 0);
173 if (mySock < 0) {
174 Debug("unable to create socket: %s\n",error_msg = strerror(errno));
175 return -1;
176 }
177
178 retval = connect(mySock, (struct sockaddr *) &addr, sizeof(addr));
179
180 if (retval < 0) {
181 Debug("unable to connect: %s\n",error_msg = strerror(errno));
182 close(mySock);
183 return -1;
184 }
185
186 Debug("connected to %s:%d, socketfd %d.\n",host->h_name,port,mySock);
187 return mySock;
188 }
189
190 /***************************************************************************
191 * Network_Init()
192 * Call before you try to use any networking functions. Returns 0 on
193 * success.
194 *********************************************************************PROTO*/
195 int
Network_Init(void)196 Network_Init(void)
197 {
198 #if HAVE_WINSOCK_H
199 WORD version_wanted = MAKEWORD(1,1);
200 WSADATA wsaData;
201
202 if ( WSAStartup(version_wanted, &wsaData) != 0 ) {
203 Debug("WARNING: Couldn't initialize Winsock 1.1\n");
204 return 1;
205 }
206 Debug("Winsock 1.1 networking available.\n");
207 return 0;
208 #endif
209 /* always works on Unix ... */
210 return 0;
211 }
212
213 /***************************************************************************
214 * Network_Quit()
215 * Call when you are done networking.
216 *********************************************************************PROTO*/
217 void
Network_Quit(void)218 Network_Quit(void)
219 {
220 #if HAVE_WINSOCK_H
221 /* Clean up windows networking */
222 if ( WSACleanup() == SOCKET_ERROR ) {
223 if ( WSAGetLastError() == WSAEINPROGRESS ) {
224 WSACancelBlockingCall();
225 WSACleanup();
226 }
227 }
228 #endif
229 return;
230 }
231