xref: /inferno-os/emu/Nt/ipif.c (revision d9c5943558618085062d60aab36ef94e12fa81c8)
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 extern int SOCK_SELECT;
13 
14 int
15 so_socket(int type)
16 {
17 	int fd, one;
18 
19 	switch(type) {
20 	default:
21 		error("bad protocol type");
22 	case S_TCP:
23 		type = SOCK_STREAM;
24 		break;
25 	case S_UDP:
26 		type = SOCK_DGRAM;
27 		break;
28 	}
29 	fd = socket(AF_INET, type, 0);
30 	if(fd < 0)
31 		oserror();
32 	if(type == SOCK_DGRAM){
33 		one = 1;
34 		setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof (one));
35 	}else{
36 		one = 1;
37 		setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one));
38 	}
39 	return fd;
40 }
41 
42 int
43 so_send(int sock, void *va, int len, void *hdr, int hdrlen)
44 {
45 	int r;
46 	struct sockaddr sa;
47 	struct sockaddr_in *sin;
48 	char *h = hdr;
49 
50 
51 	osenter();
52 	if(hdr == 0)
53 		r = send(sock, va, len, 0);
54 	else {
55 		memset(&sa, sizeof(sa), 0);
56 		sin = (struct sockaddr_in*)&sa;
57 		sin->sin_family = AF_INET;
58 		switch(hdrlen){
59 		case OUdphdrlenv4:
60 			memmove(&sin->sin_addr, h,  4);
61 			memmove(&sin->sin_port, h+8, 2);
62 			break;
63 		case OUdphdrlen:
64 			v6tov4((uchar*)&sin->sin_addr, h);
65 			memmove(&sin->sin_port, h+2*IPaddrlen, 2);	/* rport */
66 			break;
67 		default:
68 			v6tov4((uchar*)&sin->sin_addr, h);
69 			memmove(&sin->sin_port, h+3*IPaddrlen, 2);
70 			break;
71 		}
72 		r = sendto(sock, va, len, 0, &sa, sizeof(sa));
73 	}
74 	osleave();
75 	return r;
76 }
77 
78 static int
79 doselect(int sock)
80 {
81 	fd_set	waitr;
82 	struct timeval seltime;
83 
84 	up->syscall = SOCK_SELECT;
85 	FD_ZERO(&waitr);
86 	FD_SET(sock, &waitr);
87 	for(;;){
88 		int nfds;
89 		fd_set in, exc;
90 
91 		in = waitr;
92 		exc = waitr;
93 		seltime.tv_sec = 1;
94 		seltime.tv_usec = 0L;
95 		nfds = select(sizeof(fd_set)*8, &in, (fd_set*)0, &exc, &seltime);
96 		if(up->intwait) {
97 			up->intwait = 0;
98 			return -1;
99 		}
100 		if(nfds < 0) {
101 			print("select error\n");
102 			return 0;
103 		}
104 		if(FD_ISSET(sock, &in) || FD_ISSET(sock, &exc)){
105 			return 0;
106 		}
107 	}
108 }
109 
110 int
111 so_recv(int sock, void *va, int len, void *hdr, int hdrlen)
112 {
113 	int r, l;
114 	struct sockaddr sa;
115 	struct sockaddr_in *sin;
116 	char h[Udphdrlen];
117 
118 	osenter();
119 	if(doselect(sock) < 0) {
120 		osleave();
121 		return -1;
122 	}
123 	if(hdr == 0)
124 		r = recv(sock, va, len, 0);
125 	else {
126 		sin = (struct sockaddr_in*)&sa;
127 		l = sizeof(sa);
128 		r = recvfrom(sock, va, len, 0, &sa, &l);
129 		if(r >= 0) {
130 			memset(h, sizeof h, 0);
131 			switch(hdrlen){
132 			case OUdphdrlenv4:
133 				memmove(h, &sin->sin_addr, 4);
134 				memmove(h+2*IPv4addrlen, &sin->sin_port, 2);
135 				break;
136 			case OUdphdrlen:
137 				v4tov6(h, (uchar*)&sin->sin_addr);
138 				memmove(h+2*IPaddrlen, &sin->sin_port, 2);
139 				break;
140 			default:
141 				v4tov6(h, (uchar*)&sin->sin_addr);
142 				memmove(h+3*IPaddrlen, &sin->sin_port, 2);
143 				break;
144 			}
145 
146 			/* alas there's no way to get the local addr/port correctly.  Pretend. */
147 			getsockname(sock, &sa, &l);
148 			switch(hdrlen){
149 			case OUdphdrlenv4:
150 				memmove(h+IPv4addrlen, &sin->sin_addr, IPv4addrlen);
151 				memmove(h+2*IPv4addrlen+2, &sin->sin_port, 2);
152 				break;
153 			case OUdphdrlen:
154 				v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr);
155 				memmove(h+2*IPaddrlen+2, &sin->sin_port, 2);
156 				break;
157 			default:
158 				v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr);
159 				v4tov6(h+2*IPaddrlen, (uchar*)&sin->sin_addr);	/* ifcaddr */
160 				memmove(h+3*IPaddrlen+2, &sin->sin_port, 2);
161 				break;
162 			}
163 			memmove(hdr, h, hdrlen);
164 		}
165 	}
166 	osleave();
167 	return r;
168 }
169 
170 void
171 so_close(int sock)
172 {
173 	closesocket(sock);
174 }
175 
176 void
177 so_connect(int fd, unsigned long raddr, unsigned short rport)
178 {
179 	int r;
180 	struct sockaddr sa;
181 	struct sockaddr_in *sin;
182 
183 	memset(&sa, 0, sizeof(sa));
184 	sin = (struct sockaddr_in*)&sa;
185 	sin->sin_family = AF_INET;
186 	hnputs(&sin->sin_port, rport);
187 	hnputl(&sin->sin_addr.s_addr, raddr);
188 
189 	osenter();
190 	r = connect(fd, &sa, sizeof(sa));
191 	osleave();
192 	if(r < 0)
193 		oserror();
194 }
195 
196 void
197 so_getsockname(int fd, unsigned long *laddr, unsigned short *lport)
198 {
199 	int len;
200 	struct sockaddr sa;
201 	struct sockaddr_in *sin;
202 
203 	sin = (struct sockaddr_in*)&sa;
204 
205 	len = sizeof(sa);
206 	if(getsockname(fd, &sa, &len) < 0)
207 		oserror();
208 
209 	if(sin->sin_family != AF_INET || len != sizeof(*sin))
210 		error("not AF_INET");
211 
212 	*laddr = nhgetl(&sin->sin_addr.s_addr);
213 	*lport = nhgets(&sin->sin_port);
214 }
215 
216 void
217 so_listen(int fd)
218 {
219 	int r;
220 
221 	osenter();
222 	r = listen(fd, 5);
223 	osleave();
224 	if(r < 0)
225 		oserror();
226 }
227 
228 int
229 so_accept(int fd, unsigned long *raddr, unsigned short *rport)
230 {
231 	int nfd, len;
232 	struct sockaddr sa;
233 	struct sockaddr_in *sin;
234 
235 	sin = (struct sockaddr_in*)&sa;
236 
237 	len = sizeof(sa);
238 	osenter();
239 	if(doselect(fd) < 0) {
240 		osleave();
241 		return -1;
242 	}
243 	nfd = accept(fd, &sa, &len);
244 	osleave();
245 	if(nfd < 0)
246 		oserror();
247 
248 	if(sin->sin_family != AF_INET || len != sizeof(*sin))
249 		error("not AF_INET");
250 
251 	*raddr = nhgetl(&sin->sin_addr.s_addr);
252 	*rport = nhgets(&sin->sin_port);
253 	return nfd;
254 }
255 
256 void
257 so_bind(int fd, int su, unsigned long addr, unsigned short port)
258 {
259 	int i, one;
260 	struct sockaddr sa;
261 	struct sockaddr_in *sin;
262 
263 	sin = (struct sockaddr_in*)&sa;
264 
265 	one = 1;
266 //	if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0) {
267 //		oserrstr(up->genbuf, sizeof(up->genbuf));
268 //		print("setsockopt: %s", err);
269 //	}
270 
271 	if(su) {
272 		for(i = 600; i < 1024; i++) {
273 			memset(&sa, 0, sizeof(sa));
274 			sin->sin_family = AF_INET;
275 			hnputl(&sin->sin_addr.s_addr, addr);
276 			hnputs(&sin->sin_port, i);
277 
278 			if(bind(fd, &sa, sizeof(sa)) >= 0)
279 				return;
280 		}
281 		oserror();
282 	}
283 
284 	memset(&sa, 0, sizeof(sa));
285 	sin->sin_family = AF_INET;
286 	hnputl(&sin->sin_addr.s_addr, addr);
287 	hnputs(&sin->sin_port, port);
288 
289 	if(bind(fd, &sa, sizeof(sa)) < 0)
290 		oserror();
291 }
292 
293 void
294 so_setsockopt(int fd, int opt, int value)
295 {
296 	int r;
297 	struct linger l;
298 
299 	if(opt == SO_LINGER){
300 		l.l_onoff = 1;
301 		l.l_linger = (short) value;
302 		osenter();
303 		r = setsockopt(fd, SOL_SOCKET, opt, (char *)&l, sizeof(l));
304 		osleave();
305 	}else
306 		error(Ebadctl);
307 	if(r < 0)
308 		oserror();
309 }
310 
311 int
312 so_gethostbyname(char *host, char**hostv, int n)
313 {
314 	int i;
315 	unsigned char buf[32], *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 = 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 linger)
374 {
375 	int r;
376 	static struct linger l = {1, 1000};
377 
378 	osenter();
379 	if(linger)
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