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