URI: 
       tannounce.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tannounce.c (2737B)
       ---
            1 #include <u.h>
            2 #define NOPLAN9DEFINES
            3 #include <libc.h>
            4 
            5 #include <sys/socket.h>
            6 #include <netinet/in.h>
            7 #include <netinet/tcp.h>
            8 #include <sys/un.h>
            9 #include <errno.h>
           10 
           11 #undef sun
           12 #define sun sockun
           13 
           14 int
           15 _p9netfd(char *dir)
           16 {
           17         int fd;
           18 
           19         if(strncmp(dir, "/dev/fd/", 8) != 0)
           20                 return -1;
           21         fd = strtol(dir+8, &dir, 0);
           22         if(*dir != 0)
           23                 return -1;
           24         return fd;
           25 }
           26 
           27 static void
           28 putfd(char *dir, int fd)
           29 {
           30         snprint(dir, NETPATHLEN, "/dev/fd/%d", fd);
           31 }
           32 
           33 #undef unix
           34 #define unix sockunix
           35 
           36 static int
           37 addrlen(struct sockaddr_storage *ss)
           38 {
           39         switch(ss->ss_family){
           40         case AF_INET:
           41                 return sizeof(struct sockaddr_in);
           42         case AF_INET6:
           43                 return sizeof(struct sockaddr_in6);
           44         case AF_UNIX:
           45                 return sizeof(struct sockaddr_un);
           46         }
           47         return 0;
           48 }
           49 
           50 int
           51 p9announce(char *addr, char *dir)
           52 {
           53         int proto;
           54         char *buf, *unix;
           55         char *net;
           56         int port, s;
           57         int n;
           58         socklen_t sn;
           59         struct sockaddr_storage ss;
           60 
           61         buf = strdup(addr);
           62         if(buf == nil)
           63                 return -1;
           64 
           65         if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){
           66                 free(buf);
           67                 return -1;
           68         }
           69         if(strcmp(net, "tcp") == 0)
           70                 proto = SOCK_STREAM;
           71         else if(strcmp(net, "udp") == 0)
           72                 proto = SOCK_DGRAM;
           73         else if(strcmp(net, "unix") == 0)
           74                 goto Unix;
           75         else{
           76                 werrstr("can only handle tcp, udp, and unix: not %s", net);
           77                 free(buf);
           78                 return -1;
           79         }
           80         free(buf);
           81 
           82         if((s = socket(ss.ss_family, proto, 0)) < 0)
           83                 return -1;
           84         sn = sizeof n;
           85         if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
           86         && n == SOCK_STREAM){
           87                 n = 1;
           88                 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
           89         }
           90         if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
           91                 close(s);
           92                 return -1;
           93         }
           94         if(proto == SOCK_STREAM){
           95                 listen(s, 8);
           96                 putfd(dir, s);
           97         }
           98         return s;
           99 
          100 Unix:
          101         if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0)
          102                 return -1;
          103         if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
          104                 if(errno == EADDRINUSE
          105                 && connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0
          106                 && errno == ECONNREFUSED){
          107                         /* dead socket, so remove it */
          108                         remove(unix);
          109                         close(s);
          110                         if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0)
          111                                 return -1;
          112                         if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) >= 0)
          113                                 goto Success;
          114                 }
          115                 close(s);
          116                 return -1;
          117         }
          118 Success:
          119         listen(s, 8);
          120         putfd(dir, s);
          121         return s;
          122 }
          123 
          124 int
          125 p9listen(char *dir, char *newdir)
          126 {
          127         int fd, one;
          128 
          129         if((fd = _p9netfd(dir)) < 0){
          130                 werrstr("bad 'directory' in listen: %s", dir);
          131                 return -1;
          132         }
          133 
          134         if((fd = accept(fd, nil, nil)) < 0)
          135                 return -1;
          136 
          137         one = 1;
          138         setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
          139 
          140         putfd(newdir, fd);
          141         return fd;
          142 }
          143 
          144 int
          145 p9accept(int cfd, char *dir)
          146 {
          147         int fd;
          148 
          149         if((fd = _p9netfd(dir)) < 0){
          150                 werrstr("bad 'directory' in accept");
          151                 return -1;
          152         }
          153         /* need to dup because the listen fd will be closed */
          154         return dup(fd);
          155 }