xref: /inferno-os/emu/Nt/ipif.c (revision e57c7e16a3789cd4de1a3c2560d49b1ee39cd10a)
1 #define Unknown win_Unknown
2 #include        <windows.h>
3 #include        <winbase.h>
4 #include        <sys/types.h>
5 #include        <winsock.h>
6 #undef Unknown
7 #include        "dat.h"
8 #include        "fns.h"
9 #include        "ip.h"
10 #include        "error.h"
11 
12 typedef int socklen_t;	/* Windows is leading edge as always */
13 
14 
15 extern int SOCK_SELECT;
16 
17 char Enotv4[] = "address not IPv4";
18 
19 static void
20 ipw6(uchar *a, ulong w)
21 {
22 	memmove(a, v4prefix, IPv4off);
23 	memmove(a+IPv4off, &w, IPv4addrlen);
24 }
25 
26 int
27 so_socket(int type)
28 {
29 	int fd, one;
30 
31 	switch(type) {
32 	default:
33 		error("bad protocol type");
34 	case S_TCP:
35 		type = SOCK_STREAM;
36 		break;
37 	case S_UDP:
38 		type = SOCK_DGRAM;
39 		break;
40 	}
41 	fd = socket(AF_INET, type, 0);
42 	if(fd < 0)
43 		oserror();
44 	if(type == SOCK_DGRAM){
45 		one = 1;
46 		setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one));
47 	}else{
48 		one = 1;
49 		setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one));
50 	}
51 	return fd;
52 }
53 
54 int
55 so_send(int sock, void *va, int len, void *hdr, int hdrlen)
56 {
57 	int r;
58 	struct sockaddr sa;
59 	struct sockaddr_in *sin;
60 	uchar *h = hdr;
61 
62 
63 	osenter();
64 	if(hdr == 0)
65 		r = send(sock, va, len, 0);
66 	else {
67 		memset(&sa, 0, sizeof(sa));
68 		sin = (struct sockaddr_in*)&sa;
69 		sin->sin_family = AF_INET;
70 		switch(hdrlen){
71 		case OUdphdrlenv4:
72 			memmove(&sin->sin_addr, h,  4);
73 			memmove(&sin->sin_port, h+8, 2);
74 			break;
75 		case OUdphdrlen:
76 			v6tov4((uchar*)&sin->sin_addr, h);
77 			memmove(&sin->sin_port, h+2*IPaddrlen, 2);	/* rport */
78 			break;
79 		default:
80 			v6tov4((uchar*)&sin->sin_addr, h);
81 			memmove(&sin->sin_port, h+3*IPaddrlen, 2);
82 			break;
83 		}
84 		r = sendto(sock, va, len, 0, &sa, sizeof(sa));
85 	}
86 	osleave();
87 	return r;
88 }
89 
90 static int
91 doselect(int sock)
92 {
93 	fd_set	waitr;
94 	struct timeval seltime;
95 
96 	up->syscall = SOCK_SELECT;
97 	FD_ZERO(&waitr);
98 	FD_SET(sock, &waitr);
99 	for(;;){
100 		int nfds;
101 		fd_set in, exc;
102 
103 		in = waitr;
104 		exc = waitr;
105 		seltime.tv_sec = 1;
106 		seltime.tv_usec = 0L;
107 		nfds = select(sizeof(fd_set)*8, &in, (fd_set*)0, &exc, &seltime);
108 		if(up->intwait) {
109 			up->intwait = 0;
110 			return -1;
111 		}
112 		if(nfds < 0) {
113 			print("select error\n");
114 			return 0;
115 		}
116 		if(FD_ISSET(sock, &in) || FD_ISSET(sock, &exc)){
117 			return 0;
118 		}
119 	}
120 }
121 
122 int
123 so_recv(int sock, void *va, int len, void *hdr, int hdrlen)
124 {
125 	int r;
126 	socklen_t l;
127 	struct sockaddr sa;
128 	struct sockaddr_in *sin;
129 	uchar h[Udphdrlen];
130 
131 	osenter();
132 	if(doselect(sock) < 0) {
133 		osleave();
134 		return -1;
135 	}
136 	if(hdr == 0)
137 		r = recv(sock, va, len, 0);
138 	else {
139 		sin = (struct sockaddr_in*)&sa;
140 		l = sizeof(sa);
141 		r = recvfrom(sock, va, len, 0, &sa, &l);
142 		if(r >= 0) {
143 			memset(h, 0, sizeof(h));
144 			switch(hdrlen){
145 			case OUdphdrlenv4:
146 				memmove(h, &sin->sin_addr, IPv4addrlen);
147 				memmove(h+2*IPv4addrlen, &sin->sin_port, 2);
148 				break;
149 			case OUdphdrlen:
150 				v4tov6(h, (uchar*)&sin->sin_addr);
151 				memmove(h+2*IPaddrlen, &sin->sin_port, 2);
152 				break;
153 			default:
154 				v4tov6(h, (uchar*)&sin->sin_addr);
155 				memmove(h+3*IPaddrlen, &sin->sin_port, 2);
156 				break;
157 			}
158 
159 			/* alas there's no way to get the local addr/port correctly.  Pretend. */
160 			memset(&sa, 0, sizeof(sa));
161 			getsockname(sock, &sa, &l);
162 			switch(hdrlen){
163 			case OUdphdrlenv4:
164 				memmove(h+IPv4addrlen, &sin->sin_addr, IPv4addrlen);
165 				memmove(h+2*IPv4addrlen+2, &sin->sin_port, 2);
166 				break;
167 			case OUdphdrlen:
168 				v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr);
169 				memmove(h+2*IPaddrlen+2, &sin->sin_port, 2);
170 				break;
171 			default:
172 				v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr);
173 				v4tov6(h+2*IPaddrlen, (uchar*)&sin->sin_addr);	/* ifcaddr */
174 				memmove(h+3*IPaddrlen+2, &sin->sin_port, 2);
175 				break;
176 			}
177 			memmove(hdr, h, hdrlen);
178 		}
179 	}
180 	osleave();
181 	return r;
182 }
183 
184 void
185 so_close(int sock)
186 {
187 	closesocket(sock);
188 }
189 
190 void
191 so_connect(int fd, uchar *raddr, ushort rport)
192 {
193 	int r;
194 	struct sockaddr sa;
195 	struct sockaddr_in *sin;
196 
197 	if(!isv4(raddr))
198 		error(Enotv4);
199 
200 	memset(&sa, 0, sizeof(sa));
201 	sin = (struct sockaddr_in*)&sa;
202 	sin->sin_family = AF_INET;
203 	hnputs(&sin->sin_port, rport);
204 	memmove(&sin->sin_addr.s_addr, raddr+IPv4off, IPv4addrlen);
205 
206 	osenter();
207 	r = connect(fd, &sa, sizeof(sa));
208 	osleave();
209 	if(r < 0)
210 		oserror();
211 }
212 
213 void
214 so_getsockname(int fd, uchar *laddr, ushort *lport)
215 {
216 	socklen_t len;
217 	struct sockaddr sa;
218 	struct sockaddr_in *sin;
219 
220 	len = sizeof(sa);
221 	if(getsockname(fd, &sa, &len) < 0)
222 		oserror();
223 
224 	sin = (struct sockaddr_in*)&sa;
225 	if(sin->sin_family != AF_INET || len != sizeof(*sin))
226 		error(Enotv4);
227 
228 	ipw6(laddr, sin->sin_addr.s_addr);
229 	*lport = nhgets(&sin->sin_port);
230 }
231 
232 void
233 so_listen(int fd)
234 {
235 	int r;
236 
237 	osenter();
238 	r = listen(fd, 256);
239 	osleave();
240 	if(r < 0)
241 		oserror();
242 }
243 
244 int
245 so_accept(int fd, uchar *raddr, ushort *rport)
246 {
247 	int nfd;
248 	socklen_t len;
249 	struct sockaddr sa;
250 	struct sockaddr_in *sin;
251 
252 	sin = (struct sockaddr_in*)&sa;
253 
254 	len = sizeof(sa);
255 	osenter();
256 	if(doselect(fd) < 0) {
257 		osleave();
258 		return -1;
259 	}
260 	nfd = accept(fd, &sa, &len);
261 	osleave();
262 	if(nfd < 0)
263 		oserror();
264 
265 	if(sin->sin_family != AF_INET || len != sizeof(*sin))
266 		error(Enotv4);
267 
268 	ipw6(raddr, sin->sin_addr.s_addr);
269 	*rport = nhgets(&sin->sin_port);
270 	return nfd;
271 }
272 
273 void
274 so_bind(int fd, int su, uchar *addr, ushort port)
275 {
276 	int i, one;
277 	struct sockaddr sa;
278 	struct sockaddr_in *sin;
279 
280 	sin = (struct sockaddr_in*)&sa;
281 
282 	one = 1;
283 //	if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0) {
284 //		oserrstr(up->genbuf, sizeof(up->genbuf));
285 //		print("setsockopt: %s", err);
286 //	}
287 
288 	if(su) {
289 		for(i = 600; i < 1024; i++) {
290 			memset(&sa, 0, sizeof(sa));
291 			sin->sin_family = AF_INET;
292 			memmove(&sin->sin_addr.s_addr, addr+IPv4off, IPv4addrlen);
293 			hnputs(&sin->sin_port, i);
294 
295 			if(bind(fd, &sa, sizeof(sa)) >= 0)
296 				return;
297 		}
298 		oserror();
299 	}
300 
301 	memset(&sa, 0, sizeof(sa));
302 	sin->sin_family = AF_INET;
303 	memmove(&sin->sin_addr.s_addr, addr+IPv4off, IPv4addrlen);
304 	hnputs(&sin->sin_port, port);
305 
306 	if(bind(fd, &sa, sizeof(sa)) < 0)
307 		oserror();
308 }
309 
310 int
311 so_gethostbyname(char *host, char**hostv, int n)
312 {
313 	int i;
314 	char buf[32];
315 	uchar *p;
316 	struct hostent *hp;
317 
318 	hp = gethostbyname(host);
319 	if(hp == 0)
320 		return 0;
321 
322 	for(i = 0; hp->h_addr_list[i] && i < n; i++) {
323 		p = (uchar*)hp->h_addr_list[i];
324 		sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]);
325 		hostv[i] = strdup(buf);
326 		if(hostv[i] == 0)
327 			break;
328 	}
329 	return i;
330 }
331 
332 int
333 so_gethostbyaddr(char *addr, char **hostv, int n)
334 {
335 	int i;
336 	struct hostent *hp;
337 	unsigned long straddr;
338 
339 	straddr = inet_addr(addr);
340 	if(straddr == -1)
341 		return 0;
342 
343 	hp = gethostbyaddr((char *)&straddr, sizeof(straddr), AF_INET);
344 	if(hp == 0)
345 		return 0;
346 
347 	hostv[0] = strdup(hp->h_name);
348 	if(hostv[0] == 0)
349 		return 0;
350 	for(i = 1; hp->h_aliases[i-1] && i < n; i++) {
351 		hostv[i] = strdup(hp->h_aliases[i-1]);
352 		if(hostv[i] == 0)
353 			break;
354 	}
355 	return i;
356 }
357 
358 int
359 so_getservbyname(char *service, char *net, char *port)
360 {
361 	ushort p;
362 	struct servent *s;
363 
364 	s = getservbyname(service, net);
365 	if(s == 0)
366 		return -1;
367 	p = s->s_port;
368 	sprint(port, "%d", nhgets(&p));
369 	return 0;
370 }
371 
372 int
373 so_hangup(int fd, int nolinger)
374 {
375 	int r;
376 	static struct linger l = {1, 0};
377 
378 	osenter();
379 	if(nolinger)
380 		setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof(l));
381 	r = closesocket(fd);
382 	osleave();
383 	return r;
384 }
385 
386 void
387 arpadd(char *ipaddr, char *eaddr, int n)
388 {
389 	error("arp not implemented");
390 }
391 
392 int
393 so_mustbind(int restricted, int port)
394 {
395 	USED(restricted);
396 	USED(port);
397 	/* Windows requires bound sockets, even on port 0 */
398 	return 1;
399 }
400 
401 void
402 so_keepalive(int fd, int ms)
403 {
404 	int on;
405 
406 	USED(ms);
407 	on = 1;
408 	setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&on, sizeof(on));
409 }
410