dial.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       dial.c (2943B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 
            4 #undef        accept
            5 #undef        announce
            6 #undef        dial
            7 #undef        setnetmtpt
            8 #undef        hangup
            9 #undef        listen
           10 #undef        netmkaddr
           11 #undef        reject
           12 
           13 #include <sys/socket.h>
           14 #include <netinet/in.h>
           15 #include <netinet/tcp.h>
           16 #include <sys/un.h>
           17 #include <netdb.h>
           18 
           19 #undef unix
           20 #define unix xunix
           21 
           22 int
           23 p9dial(char *addr, char *local, char *dummy2, int *dummy3)
           24 {
           25         char *buf;
           26         char *net, *unix;
           27         u32int host;
           28         int port;
           29         int proto;
           30         socklen_t sn;
           31         int n;
           32         struct sockaddr_in sa, sal;        
           33         struct sockaddr_un su;
           34         int s;
           35 
           36         if(dummy2 || dummy3){
           37                 werrstr("cannot handle extra arguments in dial");
           38                 return -1;
           39         }
           40 
           41         buf = strdup(addr);
           42         if(buf == nil)
           43                 return -1;
           44 
           45         if(p9dialparse(buf, &net, &unix, &host, &port) < 0){
           46                 free(buf);
           47                 return -1;
           48         }
           49         if(strcmp(net, "unix") != 0 && host == 0){
           50                 werrstr("invalid dial address 0.0.0.0 (aka *)");
           51                 free(buf);
           52                 return -1;
           53         }
           54 
           55         if(strcmp(net, "tcp") == 0)
           56                 proto = SOCK_STREAM;
           57         else if(strcmp(net, "udp") == 0)
           58                 proto = SOCK_DGRAM;
           59         else if(strcmp(net, "unix") == 0)
           60                 goto Unix;
           61         else{
           62                 werrstr("can only handle tcp, udp, and unix: not %s", net);
           63                 free(buf);
           64                 return -1;
           65         }
           66         free(buf);
           67 
           68         if((s = socket(AF_INET, proto, 0)) < 0)
           69                 return -1;
           70                 
           71         if(local){
           72                 buf = strdup(local);
           73                 if(buf == nil){
           74                         close(s);
           75                         return -1;
           76                 }
           77                 if(p9dialparse(buf, &net, &unix, &host, &port) < 0){
           78                 badlocal:
           79                         free(buf);
           80                         close(s);
           81                         return -1;
           82                 }
           83                 if(unix){
           84                         werrstr("bad local address %s for dial %s", local, addr);
           85                         goto badlocal;
           86                 }
           87                 memset(&sal, 0, sizeof sal);
           88                 memmove(&sal.sin_addr, &local, 4);
           89                 sal.sin_family = AF_INET;
           90                 sal.sin_port = htons(port);
           91                 sn = sizeof n;
           92                 if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
           93                 && n == SOCK_STREAM){
           94                         n = 1;
           95                         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
           96                 }
           97                 if(bind(s, (struct sockaddr*)&sal, sizeof sal) < 0)
           98                         goto badlocal;
           99                 free(buf);
          100         }
          101 
          102         n = 1;
          103         setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof n);
          104         if(host != 0){
          105                 memset(&sa, 0, sizeof sa);
          106                 memmove(&sa.sin_addr, &host, 4);
          107                 sa.sin_family = AF_INET;
          108                 sa.sin_port = htons(port);
          109                 if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){
          110                         close(s);
          111                         return -1;
          112                 }
          113         }
          114         if(proto == SOCK_STREAM){
          115                 int one = 1;
          116                 setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
          117         }
          118         return s;
          119 
          120 Unix:
          121         if(local){
          122                 werrstr("local address not supported on unix network");
          123                 free(buf);
          124                 return -1;
          125         }
          126         /* Allow regular files in addition to Unix sockets. */
          127         if((s = open(unix, ORDWR)) >= 0)
          128                 return s;
          129         memset(&su, 0, sizeof su);
          130         su.sun_family = AF_UNIX;
          131         if(strlen(unix)+1 > sizeof su.sun_path){
          132                 werrstr("unix socket name too long");
          133                 free(buf);
          134                 return -1;
          135         }
          136         strcpy(su.sun_path, unix);
          137         free(buf);
          138         if((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
          139                 werrstr("socket: %r");
          140                 return -1;
          141         }
          142         if(connect(s, (struct sockaddr*)&su, sizeof su) < 0){
          143                 werrstr("connect %s: %r", su.sun_path);
          144                 close(s);
          145                 return -1;
          146         }
          147         return s;
          148 }
          149