#include #define NOPLAN9DEFINES #include #include #include #include #include #include #include #undef sun #define sun sockun extern int _p9netfd(char*); static char *unknown = "unknown"; static int convert(int s, struct sockaddr *sa, char **lsys, char **lserv, char **laddr) { struct sockaddr_un *sun; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; uchar *ip; u32int ipl; socklen_t sn; int n; char *net; switch(sa->sa_family){ case AF_INET: sin = (void*)sa; ip = (uchar*)&sin->sin_addr; ipl = *(u32int*)ip; if(ipl == 0) *lsys = strdup("*"); else *lsys = smprint("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); *lserv = smprint("%d", ntohs(sin->sin_port)); sn = sizeof n; if(getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) < 0) return -1; if(n == SOCK_STREAM) net = "tcp"; else if(n == SOCK_DGRAM) net = "udp"; else{ werrstr("unknown network type"); return -1; } *laddr = smprint("%s!%s!%s", net, *lsys, *lserv); if(*lsys == nil || *lserv == nil || *laddr == nil) return -1; return 0; case AF_INET6: sin6 = (void*)sa; if (memcmp(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) *lsys = strdup("*"); else{ *lsys = malloc(INET6_ADDRSTRLEN); inet_ntop(AF_INET6, &sin6->sin6_addr, *lsys, INET6_ADDRSTRLEN); } *lserv = smprint("%d", ntohs(sin6->sin6_port)); sn = sizeof n; if(getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) < 0) return -1; if(n == SOCK_STREAM) net = "tcp"; else if(n == SOCK_DGRAM) net = "udp"; else{ werrstr("unknown network type"); return -1; } *laddr = smprint("%s!%s!%s", net, *lsys, *lserv); if(*lsys == nil || *lserv == nil || *laddr == nil) return -1; return 0; case AF_UNIX: sun = (void*)sa; *lsys = unknown; *lserv = unknown; *laddr = smprint("unix!%s", sun->sun_path); if(*laddr == nil) return -1; return 0; default: werrstr("unknown socket family"); return -1; } } NetConnInfo* getnetconninfo(char *dir, int fd) { socklen_t sn; union { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_in6 sin6; struct sockaddr_un sun; } u; NetConnInfo *nci; if(dir){ if((fd = _p9netfd(dir)) < 0){ werrstr("no such network connection %s", dir); return nil; } } nci = mallocz(sizeof *nci, 1); if(nci == nil) goto err; nci->dir = smprint("/dev/fd/%d", fd); nci->root = strdup("/net"); nci->spec = unknown; if(nci->dir == nil || nci->root == nil) goto err; sn = sizeof u; if(getsockname(fd, &u.sa, &sn) < 0) goto err; if(convert(fd, &u.sa, &nci->lsys, &nci->lserv, &nci->laddr) < 0) goto err; sn = sizeof u; if(getpeername(fd, &u.sa, &sn) < 0) goto err; if(convert(fd, &u.sa, &nci->rsys, &nci->rserv, &nci->raddr) < 0) goto err; return nci; err: freenetconninfo(nci); return nil; } static void xfree(void *v) { if(v != nil && v != unknown) free(v); } void freenetconninfo(NetConnInfo *nci) { if(nci == nil) return; xfree(nci->dir); xfree(nci->root); xfree(nci->spec); xfree(nci->lsys); xfree(nci->lserv); xfree(nci->rsys); xfree(nci->rserv); xfree(nci->laddr); xfree(nci->raddr); free(nci); }