unofficial version 0.7.2: mainly sync/reset fixes
[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 ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
36 EventGenRec netGen =
37         { NULL, 0, FT_read, -1, NetGenFunc, EM_net, 0, "\0", 0, HEADER_SIZE3 };
38
39
40 ExtFunc int InitiateConnection(char *hostStr, short port)
41 { //connect to host
42         struct sockaddr_in addr;
43         struct hostent *host;
44
45         AtExit(CloseNet);
46         host = gethostbyname(hostStr);
47         if (!host)
48                 die("gethostbyname");
49         assert(host->h_addrtype == AF_INET);
50  again:
51         memset(&addr, 0, sizeof(addr));
52         addr.sin_family = host->h_addrtype;
53         memcpy(&addr.sin_addr, host->h_addr, host->h_length);
54         addr.sin_port = htons(port);
55         if ((netGen.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
56                 die("socket");
57         if (connect(netGen.fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
58                 if (errno != ECONNREFUSED)
59                         die("connect");
60                 close(netGen.fd);
61                 sleep(1);
62                 goto again;
63         }
64         AddEventGen(&netGen);
65         return 0;
66 } //InitiateConnection
67
68 ExtFunc void HandShake(void)
69 { //talk to your host
70         MyEvent event;
71
72         {
73                 netint4 versiondata[2];
74                 versiondata[0] = hton4(MAJOR_VERSION);
75                 versiondata[1] = hton4(PROTOCOL_VERSION);
76                 SendPacket(0, NP_hello, sizeof(versiondata), versiondata);
77         }
78
79         do {
80                 if (WaitMyEvent(&event, EM_net) == E_net)
81                 switch (event.u.net.type) {
82                         case NP_hello:
83                         {
84                                 me = event.u.net.uid;
85                                 memcpy(&Players[me], &Players[0], sizeof(Player));
86                                 fprintf(stderr, "Accepted (%s) as #%d (%s)\n",
87                                         event.u.net.data, me, Players[me].name);
88                                 SendPacket(0, NP_newPlayer,
89                                         sizeof(Player) - sizeof(Players[me].host)
90                                         - sizeof(Players[me].spy) - sizeof(Players[me].small),
91                                         &Players[me]);
92                                 break;
93                         }
94                         case NP_team:
95                         { //receive your teamnumber
96                                 memcpy(&Players[event.u.net.uid].team, event.u.net.data,
97                                         event.u.net.size);
98                                 break;
99                         } //NP_team
100                         case NP_gamedata:
101                         {
102                                 static struct {
103                                         int playerflags;
104                                         int maxplayers; //1
105                                         int started;    //2
106                                         int continuous; //3
107                                         long seed;              //4
108                                         int initspeed;  //5
109                                 } data;
110
111                                 memcpy(&data, event.u.net.data, event.u.net.size);
112                                 memcpy(&Players[me].flags, &data, sizeof(data.playerflags));
113                                 memcpy(&Players[me].flags, &data, sizeof(data.playerflags));
114                                 memcpy(&Game, &data.maxplayers,
115                                         sizeof(data) - sizeof(data.playerflags));
116                                 break;
117                         } //NP_gamedata
118                         case NP_error:
119                         {
120                                 fprintf(stderr, "Rejected by server: %s\n", event.u.net.data);
121                                 exit(1);
122                         } //NP_error
123                         default:
124                                 break;
125                 }
126                 else
127                         fatal("Hm, the party apparantly ended prematurely.");
128         }
129         while (event.u.net.type != NP_gamedata);
130 } //HandShake
131
132 ExtFunc void CheckNetConn(void)
133 { //am I necessary?
134 }
135
136
137 ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
138 { //receive
139         int result;
140         short uid, type, size;
141         netint4 *data = (netint4*)&(gen->buf);
142
143         result = MyRead(gen->fd, gen->buf + gen->bufSize,
144                 gen->bufGoal - gen->bufSize);
145         if (result < 0) {
146                 close(gen->fd);
147                 gen->fd = -1;
148                 return E_lostConn;
149         }
150         gen->bufSize += result;
151         if (gen->bufSize < gen->bufGoal)
152                 return E_none;
153         // *ugly* memcpy(data, gen->buf, sizeof(data));
154         uid = ntoh4(data[0]);
155         type = ntoh4(data[1]);
156         size = ntoh4(data[2]);
157         gen->bufGoal = size;
158         if (gen->bufSize < gen->bufGoal)
159                 return E_none;
160         gen->bufSize = 0;
161         gen->bufGoal = HEADER_SIZE3;
162         event->u.net.sender = gen->player;
163         event->u.net.uid = uid;
164         event->u.net.type = type;
165         event->u.net.size = size - HEADER_SIZE3;
166         event->u.net.data = gen->buf + HEADER_SIZE3;
167         if (type == NP_endConn) return E_lostConn;
168         return E_net;
169 } //NetGenFunc
170
171 ExtFunc void SendPacket(short uid, NetPacketType type, int size, void *data)
172 { //send shit to server
173         netint4 header[3];
174
175         header[0] = hton4(uid);
176         header[1] = hton4(type);
177         header[2] = hton4(size + HEADER_SIZE3);
178         if (MyWrite(netGen.fd, header, HEADER_SIZE3) != HEADER_SIZE3)
179                 die("write (header)");
180         if (size > 0 && data && MyWrite(netGen.fd, data, size) != size)
181                 die("write");
182 } //SendPacket
183
184 ExtFunc void CloseNet(void)
185 { //kick some connection's ass!
186         MyEvent event;
187
188         if (netGen.fd >= 0) {
189                 SendPacket(0, NP_endConn, 0, NULL);
190                 close(netGen.fd);
191                 netGen.fd = -1;
192         }
193         if (netGen.next)
194                 RemoveEventGen(&netGen);
195 } //CloseNet
196
197 /*
198  * vi: ts=4 ai
199  * vim: noai si
200  */