getnetconn.c (3240B)
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 <arpa/inet.h> 9 #include <sys/un.h> 10 #include <errno.h> 11 12 #undef sun 13 #define sun sockun 14 15 extern int _p9netfd(char*); 16 17 static char *unknown = "unknown"; 18 19 static int 20 convert(int s, struct sockaddr *sa, char **lsys, char **lserv, char **laddr) 21 { 22 struct sockaddr_un *sun; 23 struct sockaddr_in *sin; 24 struct sockaddr_in6 *sin6; 25 uchar *ip; 26 u32int ipl; 27 socklen_t sn; 28 int n; 29 char *net; 30 31 switch(sa->sa_family){ 32 case AF_INET: 33 sin = (void*)sa; 34 ip = (uchar*)&sin->sin_addr; 35 ipl = *(u32int*)ip; 36 if(ipl == 0) 37 *lsys = strdup("*"); 38 else 39 *lsys = smprint("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); 40 *lserv = smprint("%d", ntohs(sin->sin_port)); 41 sn = sizeof n; 42 if(getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) < 0) 43 return -1; 44 if(n == SOCK_STREAM) 45 net = "tcp"; 46 else if(n == SOCK_DGRAM) 47 net = "udp"; 48 else{ 49 werrstr("unknown network type"); 50 return -1; 51 } 52 *laddr = smprint("%s!%s!%s", net, *lsys, *lserv); 53 if(*lsys == nil || *lserv == nil || *laddr == nil) 54 return -1; 55 return 0; 56 case AF_INET6: 57 sin6 = (void*)sa; 58 if (memcmp(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) 59 *lsys = strdup("*"); 60 else{ 61 *lsys = malloc(INET6_ADDRSTRLEN); 62 inet_ntop(AF_INET6, &sin6->sin6_addr, *lsys, INET6_ADDRSTRLEN); 63 } 64 *lserv = smprint("%d", ntohs(sin6->sin6_port)); 65 sn = sizeof n; 66 if(getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) < 0) 67 return -1; 68 if(n == SOCK_STREAM) 69 net = "tcp"; 70 else if(n == SOCK_DGRAM) 71 net = "udp"; 72 else{ 73 werrstr("unknown network type"); 74 return -1; 75 } 76 *laddr = smprint("%s!%s!%s", net, *lsys, *lserv); 77 if(*lsys == nil || *lserv == nil || *laddr == nil) 78 return -1; 79 return 0; 80 case AF_UNIX: 81 sun = (void*)sa; 82 *lsys = unknown; 83 *lserv = unknown; 84 *laddr = smprint("unix!%s", sun->sun_path); 85 if(*laddr == nil) 86 return -1; 87 return 0; 88 default: 89 werrstr("unknown socket family"); 90 return -1; 91 } 92 } 93 94 NetConnInfo* 95 getnetconninfo(char *dir, int fd) 96 { 97 socklen_t sn; 98 union { 99 struct sockaddr sa; 100 struct sockaddr_in sin; 101 struct sockaddr_in6 sin6; 102 struct sockaddr_un sun; 103 } u; 104 NetConnInfo *nci; 105 106 if(dir){ 107 if((fd = _p9netfd(dir)) < 0){ 108 werrstr("no such network connection %s", dir); 109 return nil; 110 } 111 } 112 113 nci = mallocz(sizeof *nci, 1); 114 if(nci == nil) 115 goto err; 116 nci->dir = smprint("/dev/fd/%d", fd); 117 nci->root = strdup("/net"); 118 nci->spec = unknown; 119 if(nci->dir == nil || nci->root == nil) 120 goto err; 121 sn = sizeof u; 122 if(getsockname(fd, &u.sa, &sn) < 0) 123 goto err; 124 if(convert(fd, &u.sa, &nci->lsys, &nci->lserv, &nci->laddr) < 0) 125 goto err; 126 sn = sizeof u; 127 if(getpeername(fd, &u.sa, &sn) < 0) 128 goto err; 129 if(convert(fd, &u.sa, &nci->rsys, &nci->rserv, &nci->raddr) < 0) 130 goto err; 131 return nci; 132 133 err: 134 freenetconninfo(nci); 135 return nil; 136 } 137 138 static void 139 xfree(void *v) 140 { 141 if(v != nil && v != unknown) 142 free(v); 143 } 144 145 void 146 freenetconninfo(NetConnInfo *nci) 147 { 148 if(nci == nil) 149 return; 150 xfree(nci->dir); 151 xfree(nci->root); 152 xfree(nci->spec); 153 xfree(nci->lsys); 154 xfree(nci->lserv); 155 xfree(nci->rsys); 156 xfree(nci->rserv); 157 xfree(nci->laddr); 158 xfree(nci->raddr); 159 free(nci); 160 }