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