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