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