1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
#include <u.h>
#define NOPLAN9DEFINES
#include <libc.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include <errno.h>
#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;
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_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_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 sn;
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 sn;
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);
}
|