aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2005-02-13 19:25:44 +0000
committerrsc <devnull@localhost>2005-02-13 19:25:44 +0000
commit06f4d9201a6552b3c832fccc72ff0627986977e5 (patch)
treeb1dd465d5db4a0a7dee597436bb9592732d20d93
parent18b1814390e9d3bff470de940b448dfddf87187d (diff)
downloadplan9port-06f4d9201a6552b3c832fccc72ff0627986977e5.tar.gz
plan9port-06f4d9201a6552b3c832fccc72ff0627986977e5.tar.bz2
plan9port-06f4d9201a6552b3c832fccc72ff0627986977e5.zip
add getnetconninfo
-rw-r--r--src/lib9/getnetconn.c134
-rw-r--r--src/lib9/mkfile1
2 files changed, 135 insertions, 0 deletions
diff --git a/src/lib9/getnetconn.c b/src/lib9/getnetconn.c
new file mode 100644
index 00000000..1f239404
--- /dev/null
+++ b/src/lib9/getnetconn.c
@@ -0,0 +1,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);
+}
+
diff --git a/src/lib9/mkfile b/src/lib9/mkfile
index d118c47b..556be2f0 100644
--- a/src/lib9/mkfile
+++ b/src/lib9/mkfile
@@ -104,6 +104,7 @@ LIB9OFILES=\
getcallerpc-$OBJTYPE.$O\
getenv.$O\
getfields.$O\
+ getnetconn.$O\
getns.$O\
getuser.$O\
getwd.$O\