add linux_emul base, reorganize docs
[openbsd_emul.git] / linux_emul_base / sockdev.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ureg.h>
4 #include "dat.h"
5 #include "fns.h"
6 #include "linux.h"
7
8 typedef struct Socket Socket;
9 typedef struct Connectproc Connectproc;
10 typedef struct Listenproc Listenproc;
11
12 enum {
13 Ctlsize = 128,
14 };
15
16 struct Socket
17 {
18 Ufile;
19
20 int family;
21 int stype;
22 int protocol;
23
24 int other;
25 char net[40];
26 char name[Ctlsize];
27
28 int naddr;
29 uchar addr[40];
30
31 void *bufproc;
32 Connectproc *connectproc;
33 Listenproc *listenproc;
34
35 int connected;
36 int error;
37
38 Socket *next;
39 };
40
41 struct Connectproc
42 {
43 Ref;
44 QLock;
45 Socket *sock;
46 int notefd;
47 Uwaitq wq;
48 char str[Ctlsize];
49 };
50
51 struct Listenproc
52 {
53 Ref;
54 QLock;
55 Socket *sock;
56 int notefd;
57 Uwaitq wq;
58 Socket *q;
59 char str[Ctlsize];
60 };
61
62 enum
63 {
64 AF_UNIX =1,
65 AF_INET =2,
66 AF_INET6 =10,
67 };
68
69 enum
70 {
71 SOCK_STREAM =1,
72 SOCK_DGRAM =2,
73 SOCK_RAW =3,
74 };
75
76 static char*
77 srvname(char *npath, char *path, int len)
78 {
79 char *p;
80
81 p = strrchr(path, '/');
82 if(p == 0)
83 p = path;
84 else
85 p++;
86 snprint(npath, len, "/srv/UD.%s", p);
87 return npath;
88 }
89
90 static int
91 srvunixsock(int fd, char *path)
92 {
93 int ret;
94 int sfd;
95 char buf[8+Ctlsize+1];
96
97 sfd = -1;
98 ret = -1;
99 if(fd < 0)
100 goto out;
101 srvname(buf, path, sizeof(buf));
102 remove(buf);
103 if((sfd = create(buf, OWRITE, 0666)) < 0)
104 goto out;
105 sprint(buf, "%d", fd);
106 if(write(sfd, buf, strlen(buf)) < 0)
107 goto out;
108 ret = 0;
109 out:
110 if(sfd >= 0)
111 close(sfd);
112 return ret;
113 }
114
115 static void
116 unsrvunixsock(char *path)
117 {
118 char buf[8+Ctlsize+1];
119
120 srvname(buf, path, sizeof(buf));
121 remove(buf);
122 }
123
124 static Socket*
125 allocsock(int family, int stype, int protocol)
126 {
127 Socket *sock;
128
129 sock = kmallocz(sizeof(*sock), 1);
130 sock->family = family;
131 sock->stype = stype;
132 sock->protocol = protocol;
133 sock->fd = -1;
134 sock->other = -1;
135 sock->ref = 1;
136 sock->dev = SOCKDEV;
137 sock->mode = O_RDWR;
138
139 return sock;
140 }
141
142 static int
143 newsock(int family, int stype, int protocol)
144 {
145 Socket *sock;
146 char *net;
147 char buf[Ctlsize];
148 int pfd[2];
149 int cfd, dfd;
150 int n;
151 int err;
152
153 trace("newsock(%d, %d, %d)", family, stype, protocol);
154
155 err = -EINVAL;
156 switch(family){
157 case AF_INET:
158 case AF_INET6:
159 switch(stype){
160 case SOCK_DGRAM:
161 net = "udp";
162 break;
163 case SOCK_STREAM:
164 net = "tcp";
165 break;
166 default:
167 trace("newsock() unknown socket type %d/%d", family, stype);
168 return err;
169 }
170 break;
171 case AF_UNIX:
172 net = nil;
173 break;
174
175 default:
176 trace("newsock() unknown network family %d", family);
177 return err;
178 }
179
180 sock = allocsock(family, stype, protocol);
181 cfd = -1;
182 if(net == nil){
183 if(pipe(pfd) < 0){
184 err = mkerror();
185 goto errout;
186 }
187 sock->other = pfd[1];
188 sock->fd = pfd[0];
189 } else {
190 snprint(buf, sizeof(buf), "/net/%s/clone", net);
191 if((cfd = open(buf, ORDWR)) < 0){
192 err = mkerror();
193 goto errout;
194 }
195 n = read(cfd, buf, sizeof(buf)-1);
196 if(n < 0)
197 err = mkerror();
198 if(n <= 0)
199 goto errout;
200 buf[n] = 0;
201 n = atoi(buf);
202 snprint(buf, sizeof(buf), "/net/%s/%d/data", net, n);
203 if((dfd = open(buf, ORDWR)) < 0){
204 err = mkerror();
205 goto errout;
206 }
207 close(cfd);
208 sock->fd = dfd;
209 snprint(sock->net, sizeof(sock->net), "/net/%s", net);
210 snprint(sock->name, sizeof(sock->name), "%s/%d", sock->net, n);
211 }
212 return newfd(sock, FD_CLOEXEC);
213
214 errout:
215 close(cfd);
216 free(sock);
217 return err;
218 }
219
220 static void
221 freeconnectproc(Connectproc *cp)
222 {
223 if(cp == nil)
224 return;
225 qlock(cp);
226 cp->sock = nil;
227 if(decref(cp)){
228 write(cp->notefd, "interrupt", 9);
229 qunlock(cp);
230 return;
231 }
232 qunlock(cp);
233 close(cp->notefd);
234 free(cp);
235 }
236
237 static void
238 freelistenproc(Listenproc *lp)
239 {
240 Socket *q;
241
242 if(lp == nil)
243 return;
244 qlock(lp);
245 lp->sock = nil;
246 if(decref(lp)){
247 write(lp->notefd, "interrupt", 9);
248 qunlock(lp);
249 return;
250 }
251 while(q = lp->q){
252 lp->q = q->next;
253 putfile(q);
254 }
255 qunlock(lp);
256 close(lp->notefd);
257 free(lp);
258 }
259
260 static int
261 closesock(Ufile *file)
262 {
263 Socket *sock = (Socket*)file;
264
265 close(sock->fd);
266 close(sock->other);
267 freebufproc(sock->bufproc);
268 freeconnectproc(sock->connectproc);
269 freelistenproc(sock->listenproc);
270 return 0;
271 }
272
273
274 static void
275 connectproc(void *aux)
276 {
277 int fd, cfd, other;
278 char buf[Ctlsize], tmp[8+Ctlsize+1];
279 Connectproc *cp;
280 Socket *sock;
281 int err;
282
283 cp = (Connectproc*)aux;
284 qlock(cp);
285 if((sock = cp->sock) == nil)
286 goto out;
287
288 snprint(buf, sizeof(buf), "connectproc() %s", cp->str);
289 setprocname(buf);
290
291 err = 0;
292 switch(sock->family){
293 case AF_UNIX:
294 fd = sock->fd;
295 other = sock->other;
296 qunlock(cp);
297
298 err = -ECONNREFUSED;
299 srvname(tmp, cp->str, sizeof(buf));
300 if((cfd = open(tmp, ORDWR)) < 0)
301 break;
302
303 memset(buf, 0, sizeof(buf));
304 snprint(buf, sizeof(buf), "linuxemu.%d.%lux", getpid(), (ulong)sock);
305 if(srvunixsock(other, buf) < 0){
306 close(cfd);
307 break;
308 }
309
310 /*
311 * write Ctrlsize-1 bytes so concurrent writes will not be merged together as
312 * Ctrlsize-1 is the size used in read(). see /sys/src/ape/lib/bsd/accept.c:87
313 * this should be fixed in ape's connect() as well.
314 */
315 if(write(cfd, buf, sizeof(buf)-1) != sizeof(buf)-1){
316 close(cfd);
317 unsrvunixsock(buf);
318 break;
319 }
320 close(cfd);
321 if((read(fd, tmp, strlen(buf)) != strlen(buf)) || memcmp(buf, tmp, strlen(buf))){
322 unsrvunixsock(buf);
323 break;
324 }
325 unsrvunixsock(buf);
326 err = 0;
327 break;
328
329 default:
330 snprint(buf, sizeof(buf), "%s/ctl", sock->name);
331 qunlock(cp);
332 if((cfd = open(buf, ORDWR)) < 0){
333 err = mkerror();
334 break;
335 }
336 if(fprint(cfd, "connect %s", cp->str) < 0)
337 err = mkerror();
338 close(cfd);
339 }
340
341 qlock(cp);
342 if((sock = cp->sock) == nil)
343 goto out;
344 if(err == 0){
345 close(sock->other);
346 sock->other = -1;
347 sock->connected = 1;
348 }
349 sock->error = err;
350 out:
351 wakeq(&cp->wq, MAXPROC);
352 qunlock(cp);
353 freeconnectproc(cp);
354 }
355
356 static int
357 sockaddr2str(Socket *sock, uchar *addr, int addrlen, char *buf, int nbuf)
358 {
359 int err;
360
361 err = -EINVAL;
362 switch(sock->family){
363 case AF_INET:
364 if(addrlen < 8)
365 break;
366 err = snprint(buf, nbuf, "%d.%d.%d.%d!%d",
367 (int)(addr[4]),
368 (int)(addr[5]),
369 (int)(addr[6]),
370 (int)(addr[7]),
371 (int)(((ulong)addr[2]<<8)|(ulong)addr[3]));
372 break;
373
374 case AF_INET6:
375 /* TODO */
376 break;
377
378 case AF_UNIX:
379 if(addrlen <= 2)
380 break;
381 addrlen -= 2;
382 if(addrlen >= nbuf)
383 addrlen = nbuf-1;
384 memmove(buf, addr+2, addrlen);
385 buf[addrlen] = 0;
386 err = addrlen;
387 break;
388 }
389
390 return err;
391 }
392
393 static int
394 connectsock(Socket *sock, uchar *addr, int addrlen)
395 {
396 Connectproc *cp;
397 int err;
398 char buf[Ctlsize];
399 int pid;
400
401 if(sock->connected)
402 return -EISCONN;
403 if(sock->connectproc)
404 return -EALREADY;
405
406 if((err = sockaddr2str(sock, addr, addrlen, buf, sizeof(buf))) < 0)
407 return err;
408
409 cp = kmallocz(sizeof(*cp), 1);
410 cp->ref = 2;
411 cp->sock = sock;
412 strncpy(cp->str, buf, sizeof(cp->str));
413
414 qlock(cp);
415 sock->error = 0;
416 if((pid = procfork(connectproc, cp, 0)) < 0){
417 qunlock(cp);
418 free(cp);
419 return mkerror();
420 }
421 snprint(buf, sizeof(buf), "/proc/%d/note", pid);
422 cp->notefd = open(buf, OWRITE);
423
424 if(addrlen > sizeof(sock->addr))
425 addrlen = sizeof(sock->addr);
426 sock->naddr = addrlen;
427 memmove(sock->addr, addr, addrlen);
428
429 sock->connectproc = cp;
430 if(sock->mode & O_NONBLOCK){
431 qunlock(cp);
432 return -EINPROGRESS;
433 }
434 if((err = sleepq(&cp->wq, cp, 1)) == 0)
435 err = sock->error;
436 qunlock(cp);
437
438 /*
439 * crazy shit is going on!
440 * see: http://www.madore.org/~david/computers/connect-intr.html
441 */
442 if(err != -EINTR && err != -ERESTART){
443 sock->connectproc = nil;
444 freeconnectproc(cp);
445 }
446 return err;
447 }
448
449 static int
450 shutdownsock(Socket *sock, int how)
451 {
452 USED(how);
453
454 freebufproc(sock->bufproc);
455 sock->bufproc = nil;
456 freeconnectproc(sock->connectproc);
457 sock->connectproc = nil;
458 freelistenproc(sock->listenproc);
459 sock->listenproc = nil;
460 close(sock->fd);
461 sock->fd = -1;
462 sock->connected = 0;
463
464 return 0;
465 }
466
467 static int
468 bindsock(Socket *sock, uchar *addr, int addrlen)
469 {
470 int port;
471 int cfd;
472 char buf[Ctlsize];
473
474 port = -1;
475 switch(sock->family){
476 default:
477 return -EINVAL;
478
479 case AF_UNIX:
480 break;
481 case AF_INET:
482 if(addrlen < 4)
483 return -EINVAL;
484 port = (int)(((ulong)addr[2]<<8)|(ulong)addr[3]);
485 break;
486 case AF_INET6:
487 /* TODO */
488 return -EINVAL;
489 }
490
491 if(port >= 0){
492 snprint(buf, sizeof(buf), "%s/ctl", sock->name);
493 if((cfd = open(buf, ORDWR)) < 0)
494 return mkerror();
495 if((fprint(cfd, "announce %d", port) < 0) || (fprint(cfd, "bind %d", port) < 0)){
496 close(cfd);
497 return mkerror();
498 }
499 close(cfd);
500 }
501
502 if(addrlen > sizeof(sock->addr))
503 addrlen = sizeof(sock->addr);
504 sock->naddr = addrlen;
505 memmove(sock->addr, addr, addrlen);
506
507 return 0;
508 }
509
510 static int
511 strtoip(char *str, uchar *ip, int iplen)
512 {
513 int i, d, v6;
514 char *p, *k;
515
516 i = 0;
517 v6 = 1;
518 memset(ip, 0, iplen);
519 for(p = str; *p; p++){
520 if(*p == ':'){
521 if(p[1] == ':'){
522 p++;
523 i = iplen;
524 for(k = p+1; *k; k++){
525 if(*k == ':'){
526 v6 = 1;
527 i -= 2;
528 }
529 if(*k == '.'){
530 v6 = 0;
531 i -= 1;
532 }
533 }
534 i -= v6+1;
535 } else {
536 i += 2;
537 }
538 continue;
539 } else if(*p == '.'){
540 i++;
541 continue;
542 }
543
544 for(k = p; *k && *k != '.' && *k != ':'; k++)
545 ;
546 if(*k == '.'){
547 v6 = 0;
548 } else if(*k == ':'){
549 v6 = 1;
550 }
551
552 if(i < 0 || i + v6+1 > iplen)
553 return -1;
554
555 if(*p >= '0' && *p <= '9'){
556 d = *p - '0';
557 } else if(v6 && (*p >= 'a' && *p <= 'f')){
558 d = 0x0A + *p - 'a';
559 } else if(v6 && (*p >= 'A' && *p <= 'F')){
560 d = 0x0A + *p - 'A';
561 } else {
562 return -1;
563 }
564
565 if(v6){
566 d |= ((int)ip[i]<<12 | (int)ip[i+1]<<4);
567 ip[i] = (d>>8) & 0xFF;
568 ip[i+1] = d & 0xFF;
569 } else {
570 ip[i] = ip[i]*10 + d;
571 }
572 }
573
574 return i + v6+1;
575 }
576
577 static int
578 getsockaddr(Socket *sock, int remote, uchar *addr, int len)
579 {
580 char buf[Ctlsize];
581 char *p;
582 uchar *a;
583 int fd;
584 int n, port;
585
586 a = addr;
587 switch(sock->family){
588 case AF_UNIX:
589 if(len < sock->naddr)
590 break;
591 memmove(a, sock->addr, sock->naddr);
592 return sock->naddr;
593 case AF_INET:
594 case AF_INET6:
595 snprint(buf, sizeof(buf), "%s/%s", sock->name, remote?"remote":"local");
596 if((fd = open(buf, OREAD)) < 0)
597 return mkerror();
598 if((n = read(fd, buf, sizeof(buf)-1)) < 0){
599 close(fd);
600 return mkerror();
601 }
602 close(fd);
603 if(n > 0 && buf[n-1] == '\n')
604 n--;
605 buf[n] = 0;
606 break;
607 default:
608 return -EINVAL;
609 }
610
611 if((p = strrchr(buf, '!')) == nil)
612 return -EINVAL;
613 *p++ = 0;
614 port = atoi(p);
615
616 trace("getsockaddr(): ip=%s port=%d", buf, port);
617
618 switch(sock->family){
619 case AF_INET:
620 if(len < 8)
621 break;
622 if(len > 16)
623 len = 16;
624 memset(a, 0, len);
625 a[0] = sock->family & 0xFF;
626 a[1] = (sock->family>>8) & 0xFF;
627 a[2] = (port >> 8) & 0xFF;
628 a[3] = port & 0xFF;
629 if(strtoip(buf, &a[4], 4) < 0)
630 break;
631 return len;
632
633 case AF_INET6:
634 /* TODO */
635 break;
636 }
637
638 return -EINVAL;
639 }
640
641 static void
642 listenproc(void *aux)
643 {
644 Listenproc *lp;
645 Socket *sock, *q;
646 char buf[Ctlsize], tmp[8+Ctlsize+1];
647 int cfd, fd, n;
648
649 lp = (Listenproc*)aux;
650 qlock(lp);
651 if((sock = lp->sock) == nil)
652 goto out;
653
654 snprint(buf, sizeof(buf), "listenproc() %s", lp->str);
655 setprocname(buf);
656
657 for(;;){
658 n = 0;
659 cfd = -1;
660 switch(sock->family){
661 case AF_UNIX:
662 srvunixsock(sock->other, lp->str);
663 close(sock->other);
664 sock->other = -1;
665 fd = sock->fd;
666 qunlock(lp);
667 n = read(fd, buf, sizeof(buf)-1);
668 qlock(lp);
669 break;
670
671 default:
672 snprint(buf, sizeof(buf), "%s/listen", sock->name);
673 qunlock(lp);
674 if((cfd = open(buf, ORDWR)) >= 0)
675 n = read(cfd, buf, sizeof(buf)-1);
676 qlock(lp);
677 if(n <= 0)
678 close(cfd);
679 }
680 if(n <= 0)
681 break;
682 buf[n] = 0;
683
684 if((sock = lp->sock) == nil){
685 close(cfd);
686 break;
687 }
688
689 switch(sock->family){
690 case AF_UNIX:
691 srvname(tmp, buf, sizeof(tmp));
692 if((fd = open(tmp, ORDWR)) < 0)
693 break;
694 unsrvunixsock(buf);
695 if(write(fd, buf, strlen(buf)) != strlen(buf)){
696 close(fd);
697 fd = -1;
698 }
699 buf[0] = 0;
700 break;
701
702 default:
703 n = atoi(buf);
704 snprint(buf, sizeof(buf), "%s/%d", sock->net, n);
705 snprint(tmp, sizeof(tmp), "%s/data", buf);
706 fd = open(tmp, ORDWR);
707 close(cfd);
708 break;
709 }
710
711 if(fd < 0)
712 continue;
713
714 q = allocsock(sock->family, sock->stype, sock->protocol);
715 strncpy(q->net, sock->net, sizeof(q->net));
716 strncpy(q->name, buf, sizeof(q->name));
717
718 if(sock->family == AF_UNIX){
719 memmove(q->addr, sock->addr, q->naddr = sock->naddr);
720 } else {
721 q->naddr = getsockaddr(q, 0, q->addr, sizeof(q->addr));
722 }
723
724 q->fd = fd;
725 q->connected = 1;
726 q->next = lp->q;
727 lp->q = q;
728 wakeq(&lp->wq, MAXPROC);
729 }
730
731 if(sock->family == AF_UNIX)
732 unsrvunixsock(lp->str);
733 out:
734 wakeq(&lp->wq, MAXPROC);
735 qunlock(lp);
736 freelistenproc(lp);
737 }
738
739
740 static int
741 listensock(Socket *sock)
742 {
743 Listenproc *lp;
744 int pid, err;
745 char buf[Ctlsize];
746
747 trace("listensock()");
748
749 if(sock->listenproc)
750 return 0;
751 if((err = sockaddr2str(sock, sock->addr, sock->naddr, buf, sizeof(buf))) < 0)
752 return err;
753
754 lp = kmallocz(sizeof(*lp), 1);
755 lp->ref = 2;
756 lp->sock = sock;
757 strncpy(lp->str, buf, sizeof(lp->str));
758
759 qlock(lp);
760 if((pid = procfork(listenproc, lp, 0)) < 0){
761 qunlock(lp);
762 free(lp);
763 return mkerror();
764 }
765 snprint(buf, sizeof(buf), "/proc/%d/note", pid);
766 lp->notefd = open(buf, OWRITE);
767 sock->listenproc = lp;
768 qunlock(lp);
769
770 return 0;
771 }
772
773 static int
774 getsockname(Socket *sock, uchar *addr, int *paddrlen)
775 {
776 int ret;
777
778 trace("getsockname(%p, %p, %p (%x))", sock, addr, paddrlen, paddrlen ? *paddrlen : 0);
779
780 if(addr == nil || paddrlen == nil)
781 return -EINVAL;
782
783 ret = sock->naddr;
784 memmove(addr, sock->addr, ret);
785 *paddrlen = ret;
786
787 return ret;
788 }
789
790 static int
791 getpeername(Socket *sock, uchar *addr, int *paddrlen)
792 {
793 int ret;
794
795 trace("getpeername(%p, %p, %p (%x))", sock, addr, paddrlen, paddrlen ? *paddrlen : 0);
796
797 if(addr == nil || paddrlen == nil)
798 return -EINVAL;
799
800 if((ret = getsockaddr(sock, 1, addr, *paddrlen)) > 0)
801 *paddrlen = ret;
802 return ret;
803 }
804
805 static int
806 acceptsock(Socket *sock, uchar *addr, int *paddrlen)
807 {
808 Listenproc *lp;
809 Socket *nsock;
810 int err;
811
812 trace("acceptsock(%p, %p, %p (%x))", sock, addr, paddrlen, paddrlen ? *paddrlen : 0);
813
814 if((lp = sock->listenproc) == nil)
815 return -EINVAL;
816
817 qlock(lp);
818 for(;;){
819 if(nsock = lp->q){
820 lp->q = nsock->next;
821 nsock->next = nil;
822 qunlock(lp);
823
824 if(addr != nil && paddrlen != nil){
825 err = getsockaddr(nsock, 1, addr, *paddrlen);
826 *paddrlen = err < 0 ? 0 : err;
827 }
828 return newfd(nsock, FD_CLOEXEC);
829 }
830
831 if(sock->mode & O_NONBLOCK){
832 err = -EAGAIN;
833 break;
834 }
835
836 if((err = sleepq(&lp->wq, lp, 1)) < 0)
837 break;
838 }
839 qunlock(lp);
840
841 return err;
842 }
843
844 static int
845 socketpair(int family, int stype, int protocol, int sv[2])
846 {
847 Socket *sock;
848 int p[2];
849 int i, fd;
850
851 trace("socketpair(%d, %d, %d, %p)", family, stype, protocol, sv);
852
853 if(family != AF_UNIX)
854 return -EAFNOSUPPORT;
855 if(pipe(p) < 0)
856 return mkerror();
857 for(i=0; i<2; i++){
858 sock = allocsock(family, stype, protocol);
859 sock->fd = p[i];
860 sock->connected = 1;
861 if((fd = newfd(sock, FD_CLOEXEC)) < 0){
862 if(i > 0)
863 sys_close(sv[0]);
864 close(p[0]);
865 close(p[1]);
866 return fd;
867 }
868 sv[i] = fd;
869 }
870 return 0;
871 }
872
873 static void*
874 bufprocsock(Socket *sock)
875 {
876 if(sock->bufproc == nil)
877 sock->bufproc = newbufproc(sock->fd);
878 return sock->bufproc;
879 }
880
881 static int
882 pollsock(Ufile *file, void *tab)
883 {
884 Socket *sock = (Socket*)file;
885 Listenproc *lp;
886 Connectproc *cp;
887
888 if(!sock->connected){
889 if(lp = sock->listenproc){
890 qlock(lp);
891 pollwait(file, &lp->wq, tab);
892 if(lp->q){
893 qunlock(lp);
894 return POLLIN;
895 }
896 qunlock(lp);
897 }
898 if(cp = sock->connectproc){
899 qlock(cp);
900 pollwait(file, &cp->wq, tab);
901 if(sock->error < 0){
902 qunlock(cp);
903 return POLLOUT;
904 }
905 qunlock(cp);
906 }
907 return 0;
908 }
909
910 return pollbufproc(bufprocsock(sock), sock, tab);
911 }
912
913 static int
914 readsock(Ufile *file, void *buf, int len, vlong)
915 {
916 Socket *sock = (Socket*)file;
917 int ret;
918
919 if(!sock->connected)
920 return -ENOTCONN;
921 if((sock->mode & O_NONBLOCK) || (sock->bufproc != nil)){
922 ret = readbufproc(bufprocsock(sock), buf, len, 0, (sock->mode & O_NONBLOCK));
923 } else {
924 if(notifyme(1))
925 return -ERESTART;
926 ret = read(sock->fd, buf, len);
927 notifyme(0);
928 if(ret < 0)
929 ret = mkerror();
930 }
931 return ret;
932 }
933
934 extern int pipewrite(int fd, void *buf, int len);
935
936 static int
937 writesock(Ufile *file, void *buf, int len, vlong)
938 {
939 Socket *sock = (Socket*)file;
940 int ret;
941
942 if(!sock->connected)
943 return -ENOTCONN;
944 if(sock->family == AF_UNIX)
945 return pipewrite(sock->fd, buf, len);
946 if(notifyme(1))
947 return -ERESTART;
948 ret = write(sock->fd, buf, len);
949 notifyme(0);
950 if(ret < 0)
951 ret = mkerror();
952 return ret;
953 }
954
955 static int
956 ioctlsock(Ufile *file, int cmd, void *arg)
957 {
958 Socket *sock = (Socket*)file;
959
960 switch(cmd){
961 default:
962 return -ENOTTY;
963 case 0x541B:
964 {
965 int r;
966
967 if(arg == nil)
968 return -EINVAL;
969 if((r = nreadablebufproc(bufprocsock(sock))) < 0){
970 *((int*)arg) = 0;
971 return r;
972 }
973 *((int*)arg) = r;
974 }
975 return 0;
976 }
977 }
978
979 static int
980 sendto(Socket *sock, void *data, int len, int, uchar *, int)
981 {
982 trace("sendto(%p, %p, %d, ...)", sock, data, len);
983
984 return writesock(sock, data, len, sock->off);
985 }
986
987 static int
988 recvfrom(Socket *sock, void *data, int len, int flags, uchar *addr, int addrlen)
989 {
990 int ret;
991
992 trace("recvfrom(%p, %p, %d, %x, %p, %d)", sock, data, len, flags, addr, addrlen);
993
994 if(flags & 2){
995 if(!sock->connected)
996 return -ENOTCONN;
997 ret = readbufproc(bufprocsock(sock), data, len, 1, 1);
998 } else {
999 ret = readsock(sock, data, len, sock->off);
1000 }
1001 if(addr){
1002 memmove(addr, sock->addr, sock->naddr);
1003 }
1004 return ret;
1005 }
1006
1007 enum {
1008 SOL_SOCKET = 1,
1009
1010 SO_DEBUG = 1,
1011 SO_REUSEADDR,
1012 SO_TYPE,
1013 SO_ERROR,
1014 };
1015
1016 static int
1017 getoptsock(Socket *sock, int lvl, int opt, char *ov, int *ol)
1018 {
1019 trace("getoptsock(%p, %d, %d, %p, %p)", sock, lvl, opt, ov, ol);
1020
1021 switch(lvl){
1022 default:
1023 Default:
1024 return -EINVAL;
1025
1026 case SOL_SOCKET:
1027 switch(opt){
1028 default:
1029 goto Default;
1030 case SO_ERROR:
1031 *ol = sizeof(int);
1032 *((int*)ov) = sock->error;
1033 break;
1034 }
1035 break;
1036 }
1037
1038 return 0;
1039 }
1040
1041 enum {
1042 SYS_SOCKET=1,
1043 SYS_BIND,
1044 SYS_CONNECT,
1045 SYS_LISTEN,
1046 SYS_ACCEPT,
1047 SYS_GETSOCKNAME,
1048 SYS_GETPEERNAME,
1049 SYS_SOCKETPAIR,
1050 SYS_SEND,
1051 SYS_RECV,
1052 SYS_SENDTO,
1053 SYS_RECVFROM,
1054 SYS_SHUTDOWN,
1055 SYS_SETSOCKOPT,
1056 SYS_GETSOCKOPT,
1057 SYS_SENDMSG,
1058 SYS_RECVMSG,
1059 };
1060
1061 int sys_linux_socketcall(int call, int *arg)
1062 {
1063 Socket *sock;
1064 int ret;
1065
1066 trace("sys_linux_socketcall(%d, %p)", call, arg);
1067
1068 if(call == SYS_SOCKET)
1069 return newsock(arg[0], arg[1], arg[2]);
1070
1071 if(call == SYS_SOCKETPAIR)
1072 return socketpair(arg[0], arg[1], arg[2], (int*)arg[3]);
1073
1074 if((sock = (Socket*)fdgetfile(arg[0])) == nil)
1075 return -EBADF;
1076
1077 if(sock->dev != SOCKDEV){
1078 putfile(sock);
1079 return -ENOTSOCK;
1080 }
1081
1082 ret = -1;
1083 switch(call){
1084 case SYS_CONNECT:
1085 ret = connectsock(sock, (void*)arg[1], arg[2]);
1086 break;
1087 case SYS_SENDTO:
1088 ret = sendto(sock, (void*)arg[1], arg[2], arg[3], (void*)arg[4], arg[5]);
1089 break;
1090 case SYS_RECVFROM:
1091 ret = recvfrom(sock, (void*)arg[1], arg[2], arg[3], (void*)arg[4], arg[5]);
1092 break;
1093 case SYS_SEND:
1094 ret = sendto(sock, (void*)arg[1], arg[2], arg[3], nil, 0);
1095 break;
1096 case SYS_RECV:
1097 ret = recvfrom(sock, (void*)arg[1], arg[2], arg[3], nil, 0);
1098 break;
1099 case SYS_GETSOCKNAME:
1100 ret = getsockname(sock, (void*)arg[1], (void*)arg[2]);
1101 break;
1102 case SYS_GETPEERNAME:
1103 ret = getpeername(sock, (void*)arg[1], (void*)arg[2]);
1104 break;
1105 case SYS_SHUTDOWN:
1106 ret = shutdownsock(sock, arg[1]);
1107 break;
1108 case SYS_BIND:
1109 ret = bindsock(sock, (void*)arg[1], arg[2]);
1110 break;
1111 case SYS_LISTEN:
1112 ret = listensock(sock);
1113 break;
1114 case SYS_ACCEPT:
1115 ret = acceptsock(sock, (void*)arg[1], (void*)arg[2]);
1116 break;
1117 case SYS_SETSOCKOPT:
1118 ret = 0;
1119 break;
1120 case SYS_GETSOCKOPT:
1121 ret = getoptsock(sock, (int)arg[1], (int)arg[2], (char*)arg[3], (int*)arg[4]);
1122 break;
1123 case SYS_SENDMSG:
1124 case SYS_RECVMSG:
1125 default:
1126 trace("socketcall(): call %d not implemented", call);
1127 }
1128
1129 putfile(sock);
1130
1131 return ret;
1132 }
1133
1134 static void
1135 fillstat(Ustat *s)
1136 {
1137 s->mode = 0666 | S_IFSOCK;
1138 s->uid = current->uid;
1139 s->gid = current->gid;
1140 s->size = 0;
1141 }
1142
1143 static int
1144 fstatsock(Ufile *, Ustat *s)
1145 {
1146 fillstat(s);
1147 return 0;
1148 };
1149
1150 static Udev sockdev =
1151 {
1152 .read = readsock,
1153 .write = writesock,
1154 .poll = pollsock,
1155 .close = closesock,
1156 .ioctl = ioctlsock,
1157 .fstat = fstatsock,
1158 };
1159
1160 void sockdevinit(void)
1161 {
1162 devtab[SOCKDEV] = &sockdev;
1163 }