Merge branch 'upstream'
[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         AtExit(CloseNet);
46 }
47
48 ExtFunc int WaitForConnection(char *portStr)
49 {
50         struct sockaddr_in addr;
51         struct hostent *host;
52         int sockListen;
53         int addrLen;
54         short port;
55         int val1;
56         struct linger val2;
57
58         if (portStr)
59                 port = atoi(portStr);   /* XXX Error checking */
60         else
61                 port = DEFAULT_PORT;
62         memset(&addr, 0, sizeof(addr));
63         addr.sin_family = AF_INET;
64         addr.sin_addr.s_addr = htonl(INADDR_ANY);
65         addr.sin_port = htons(port);
66         sockListen = socket(AF_INET, SOCK_STREAM, 0);
67         if (sockListen < 0)
68                 die("socket");
69         val1 = 1;
70         setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR,
71                         (void *)&val1, sizeof(val1));
72         if (bind(sockListen, (struct sockaddr *)&addr, sizeof(addr)) < 0)
73                 die("bind");
74         if (listen(sockListen, 1) < 0)
75                 die("listen");
76         addrLen = sizeof(addr);
77         sock = accept(sockListen, (struct sockaddr *)&addr, &addrLen);
78         if (sock < 0)
79                 die("accept");
80         close(sockListen);
81         val2.l_onoff = 1;
82         val2.l_linger = 0;
83         setsockopt(sock, SOL_SOCKET, SO_LINGER,
84                         (void *)&val2, sizeof(val2));
85         netGen.fd = sock;
86         strcpy(opponentHost, "???");
87         if (addr.sin_family == AF_INET) {
88                 host = gethostbyaddr((void *)&addr.sin_addr,
89                                 sizeof(struct in_addr), AF_INET);
90                 if (host) {
91                         strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
92                         opponentHost[sizeof(opponentHost)-1] = 0;
93                 }
94         }
95         AddEventGen(&netGen);
96         isServer = 1;
97         return 0;
98 }
99
100 ExtFunc int InitiateConnection(char *hostStr, char *portStr)
101 {
102         struct sockaddr_in addr;
103         struct hostent *host;
104         short port;
105         int mySock;
106
107         if (portStr)
108                 port = atoi(portStr);   /* XXX Error checking */
109         else
110                 port = DEFAULT_PORT;
111         host = gethostbyname(hostStr);
112         if (!host)
113                 die("gethostbyname");
114         assert(host->h_addrtype == AF_INET);
115         strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
116         opponentHost[sizeof(opponentHost)-1] = 0;
117  again:
118         memset(&addr, 0, sizeof(addr));
119         addr.sin_family = host->h_addrtype;
120         memcpy(&addr.sin_addr, host->h_addr, host->h_length);
121         addr.sin_port = htons(port);
122         mySock = socket(AF_INET, SOCK_STREAM, 0);
123         if (mySock < 0)
124                 die("socket");
125         if (connect(mySock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
126                 if (errno != ECONNREFUSED)
127                         die("connect");
128                 close(mySock);
129                 sleep(1);
130                 goto again;
131         }
132         netGen.fd = sock = mySock;
133         AddEventGen(&netGen);
134         return 0;
135 }
136
137 static MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
138 {
139         int result;
140         short type, size;
141         netint2 data[2];
142
143         result = MyRead(sock, netBuf + netBufSize, netBufGoal - netBufSize);
144         if (result < 0) {
145                 lostConn = 1;
146                 return E_lostConn;
147         }
148         netBufSize += result;
149         if (netBufSize < netBufGoal)
150                 return E_none;
151         memcpy(data, netBuf, sizeof(data));
152         type = ntoh2(data[0]);
153         size = ntoh2(data[1]);
154         if (size >= sizeof(netBuf))
155                 fatal("Received an invalid packet (too large), possibly an attempt\n"
156                           "  to exploit a vulnerability in versions before 0.52 !");
157         netBufGoal = size;
158         if (netBufSize < netBufGoal)
159                 return E_none;
160         netBufSize = 0;
161         netBufGoal = HEADER_SIZE;
162         event->u.net.type = type;
163         event->u.net.size = size - HEADER_SIZE;
164         event->u.net.data = netBuf + HEADER_SIZE;
165         if (type == NP_endConn) {
166                 gotEndConn = 1;
167                 return E_lostConn;
168         }
169         else if (type == NP_byeBye) {
170                 lostConn = 1;
171                 return E_lostConn;
172         }
173         return E_net;
174 }
175
176 ExtFunc void CheckNetConn(void)
177 {
178 }
179
180 ExtFunc void SendPacket(NetPacketType type, int size, void *data)
181 {
182         netint2 header[2];
183
184         header[0] = hton2(type);
185         header[1] = hton2(size + HEADER_SIZE);
186         if (MyWrite(sock, header, HEADER_SIZE) != HEADER_SIZE)
187                 die("write");
188         if (size > 0 && data && MyWrite(sock, data, size) != size)
189                 die("write");
190 }
191
192 ExtFunc void CloseNet(void)
193 {
194         MyEvent event;
195
196         if (sock >= 0) {
197                 if (!lostConn) {
198                         SendPacket(NP_endConn, 0, NULL);
199                         if (isServer) {
200                                 while (!lostConn)
201                                         WaitMyEvent(&event, EM_net);
202                         }
203                         else {
204                                 while (!gotEndConn)
205                                         WaitMyEvent(&event, EM_net);
206                                 SendPacket(NP_byeBye, 0, NULL);
207                         }
208                 }
209                 close(sock);
210                 sock = -1;
211         }
212         if (netGen.next)
213                 RemoveEventGen(&netGen);
214 }
215
216 /*
217  * vi: ts=4 ai
218  * vim: noai si
219  */