Imported Debian patch 0.52-2
[pkg/netris.git] / inet.c
1 /*
2  * Netris -- A free networked version of T*tris
3  * Copyright (C) 1994,1995,1996  Mark H. Weaver <mhw@netris.org>
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id: inet.c,v 1.18 1996/02/09 08:22:13 mhw Exp $
20  */
21
22 #include "netris.h"
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <netdb.h>
29 #include <string.h>
30 #include <errno.h>
31
32 #define HEADER_SIZE sizeof(netint2[2])
33
34 static MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
35
36 static int sock = -1;
37 static EventGenRec netGen = { NULL, 0, FT_read, -1, NetGenFunc, EM_net };
38
39 static char netBuf[64];
40 static int netBufSize, netBufGoal = HEADER_SIZE;
41 static int isServer, lostConn, gotEndConn;
42
43 ExtFunc void InitNet(void)
44 {
45         lostConn = 0;
46         gotEndConn = 0;
47         AtExit(CloseNet);
48 }
49
50 ExtFunc int WaitForConnection(char *portStr)
51 {
52         struct sockaddr_in addr;
53         struct hostent *host;
54         int sockListen;
55         int addrLen;
56         short port;
57         int val1;
58         struct linger val2;
59
60         if (portStr)
61                 port = atoi(portStr);   /* XXX Error checking */
62         else
63                 port = DEFAULT_PORT;
64         memset(&addr, 0, sizeof(addr));
65         addr.sin_family = AF_INET;
66         addr.sin_addr.s_addr = htonl(INADDR_ANY);
67         addr.sin_port = htons(port);
68         sockListen = socket(AF_INET, SOCK_STREAM, 0);
69         if (sockListen < 0)
70                 die("socket");
71         val1 = 1;
72         setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR,
73                         (void *)&val1, sizeof(val1));
74         if (bind(sockListen, (struct sockaddr *)&addr, sizeof(addr)) < 0)
75                 die("bind");
76         if (listen(sockListen, 1) < 0)
77                 die("listen");
78         addrLen = sizeof(addr);
79         sock = accept(sockListen, (struct sockaddr *)&addr, &addrLen);
80         if (sock < 0)
81                 die("accept");
82         close(sockListen);
83         val2.l_onoff = 1;
84         val2.l_linger = 0;
85         setsockopt(sock, SOL_SOCKET, SO_LINGER,
86                         (void *)&val2, sizeof(val2));
87         netGen.fd = sock;
88         strcpy(opponentHost, "???");
89         if (addr.sin_family == AF_INET) {
90                 host = gethostbyaddr((void *)&addr.sin_addr,
91                                 sizeof(struct in_addr), AF_INET);
92                 if (host) {
93                         strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
94                         opponentHost[sizeof(opponentHost)-1] = 0;
95                 }
96         }
97         AddEventGen(&netGen);
98         isServer = 1;
99         return 0;
100 }
101
102 ExtFunc int InitiateConnection(char *hostStr, char *portStr)
103 {
104         struct sockaddr_in addr;
105         struct hostent *host;
106         short port;
107         int mySock;
108
109         if (portStr)
110                 port = atoi(portStr);   /* XXX Error checking */
111         else
112                 port = DEFAULT_PORT;
113         host = gethostbyname(hostStr);
114         if (!host)
115                 die("gethostbyname");
116         assert(host->h_addrtype == AF_INET);
117         strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
118         opponentHost[sizeof(opponentHost)-1] = 0;
119  again:
120         memset(&addr, 0, sizeof(addr));
121         addr.sin_family = host->h_addrtype;
122         memcpy(&addr.sin_addr, host->h_addr, host->h_length);
123         addr.sin_port = htons(port);
124         mySock = socket(AF_INET, SOCK_STREAM, 0);
125         if (mySock < 0)
126                 die("socket");
127         if (connect(mySock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
128                 if (errno != ECONNREFUSED)
129                         die("connect");
130                 close(mySock);
131                 sleep(1);
132                 goto again;
133         }
134         netGen.fd = sock = mySock;
135         AddEventGen(&netGen);
136         return 0;
137 }
138
139 static MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
140 {
141         int result;
142         short type, size;
143         netint2 data[2];
144
145         result = MyRead(sock, netBuf + netBufSize, netBufGoal - netBufSize);
146         if (result < 0) {
147                 lostConn = 1;
148                 return E_lostConn;
149         }
150         netBufSize += result;
151         if (netBufSize < netBufGoal)
152                 return E_none;
153         memcpy(data, netBuf, sizeof(data));
154         type = ntoh2(data[0]);
155         size = ntoh2(data[1]);
156         if (size >= sizeof(netBuf))
157                 fatal("Received an invalid packet (too large), possibly an attempt\n"
158                           "  to exploit a vulnerability in versions before 0.52 !");
159         netBufGoal = size;
160         if (netBufSize < netBufGoal)
161                 return E_none;
162         netBufSize = 0;
163         netBufGoal = HEADER_SIZE;
164         event->u.net.type = type;
165         event->u.net.size = size - HEADER_SIZE;
166         event->u.net.data = netBuf + HEADER_SIZE;
167         if (type == NP_endConn) {
168                 gotEndConn = 1;
169                 return E_lostConn;
170         }
171         else if (type == NP_byeBye) {
172                 lostConn = 1;
173                 return E_lostConn;
174         }
175         return E_net;
176 }
177
178 ExtFunc void CheckNetConn(void)
179 {
180 }
181
182 ExtFunc void SendPacket(NetPacketType type, int size, void *data)
183 {
184         netint2 header[2];
185
186         header[0] = hton2(type);
187         header[1] = hton2(size + HEADER_SIZE);
188         if (MyWrite(sock, header, HEADER_SIZE) != HEADER_SIZE)
189                 die("write");
190         if (size > 0 && data && MyWrite(sock, data, size) != size)
191                 die("write");
192 }
193
194 ExtFunc void CloseNet(void)
195 {
196         MyEvent event;
197
198         if (sock >= 0) {
199                 if (!lostConn) {
200                         SendPacket(NP_endConn, 0, NULL);
201                         if (isServer) {
202                                 while (!lostConn)
203                                         WaitMyEvent(&event, EM_net);
204                         }
205                         else {
206                                 while (!gotEndConn)
207                                         WaitMyEvent(&event, EM_net);
208                                 SendPacket(NP_byeBye, 0, NULL);
209                         }
210                 }
211                 close(sock);
212                 sock = -1;
213         }
214         if (netGen.next)
215                 RemoveEventGen(&netGen);
216 }
217
218 /*
219  * vi: ts=4 ai
220  * vim: noai si
221  */