aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/fossil/9lstn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/fossil/9lstn.c')
-rw-r--r--src/cmd/fossil/9lstn.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/cmd/fossil/9lstn.c b/src/cmd/fossil/9lstn.c
new file mode 100644
index 00000000..9ba508f4
--- /dev/null
+++ b/src/cmd/fossil/9lstn.c
@@ -0,0 +1,184 @@
+#include "stdinc.h"
+
+#include "9.h"
+
+typedef struct Lstn Lstn;
+struct Lstn {
+ int afd;
+ int flags;
+ char* address;
+ char dir[NETPATHLEN];
+
+ Lstn* next;
+ Lstn* prev;
+};
+
+static struct {
+ VtLock* lock;
+
+ Lstn* head;
+ Lstn* tail;
+} lbox;
+
+static void
+lstnFree(Lstn* lstn)
+{
+ vtLock(lbox.lock);
+ if(lstn->prev != nil)
+ lstn->prev->next = lstn->next;
+ else
+ lbox.head = lstn->next;
+ if(lstn->next != nil)
+ lstn->next->prev = lstn->prev;
+ else
+ lbox.tail = lstn->prev;
+ vtUnlock(lbox.lock);
+
+ if(lstn->afd != -1)
+ close(lstn->afd);
+ vtMemFree(lstn->address);
+ vtMemFree(lstn);
+}
+
+static void
+lstnListen(void* a)
+{
+ Lstn *lstn;
+ int dfd, lfd;
+ char newdir[NETPATHLEN];
+
+ vtThreadSetName("listen");
+
+ lstn = a;
+ for(;;){
+ if((lfd = listen(lstn->dir, newdir)) < 0){
+ fprint(2, "listen: listen '%s': %r", lstn->dir);
+ break;
+ }
+ if((dfd = accept(lfd, newdir)) >= 0)
+ conAlloc(dfd, newdir, lstn->flags);
+ else
+ fprint(2, "listen: accept %s: %r\n", newdir);
+ close(lfd);
+ }
+ lstnFree(lstn);
+}
+
+static Lstn*
+lstnAlloc(char* address, int flags)
+{
+ int afd;
+ Lstn *lstn;
+ char dir[NETPATHLEN];
+
+ vtLock(lbox.lock);
+ for(lstn = lbox.head; lstn != nil; lstn = lstn->next){
+ if(strcmp(lstn->address, address) != 0)
+ continue;
+ vtSetError("listen: already serving '%s'", address);
+ vtUnlock(lbox.lock);
+ return nil;
+ }
+
+ if((afd = announce(address, dir)) < 0){
+ vtSetError("listen: announce '%s': %r", address);
+ vtUnlock(lbox.lock);
+ return nil;
+ }
+
+ lstn = vtMemAllocZ(sizeof(Lstn));
+ lstn->afd = afd;
+ lstn->address = vtStrDup(address);
+ lstn->flags = flags;
+ memmove(lstn->dir, dir, NETPATHLEN);
+
+ if(lbox.tail != nil){
+ lstn->prev = lbox.tail;
+ lbox.tail->next = lstn;
+ }
+ else{
+ lbox.head = lstn;
+ lstn->prev = nil;
+ }
+ lbox.tail = lstn;
+ vtUnlock(lbox.lock);
+
+ if(vtThread(lstnListen, lstn) < 0){
+ vtSetError("listen: thread '%s': %r", lstn->address);
+ lstnFree(lstn);
+ return nil;
+ }
+
+ return lstn;
+}
+
+static int
+cmdLstn(int argc, char* argv[])
+{
+ int dflag, flags;
+ Lstn *lstn;
+ char *usage = "usage: listen [-dIN] [address]";
+
+ dflag = 0;
+ flags = 0;
+ ARGBEGIN{
+ default:
+ return cliError(usage);
+ case 'd':
+ dflag = 1;
+ break;
+ case 'I':
+ flags |= ConIPCheck;
+ break;
+ case 'N':
+ flags |= ConNoneAllow;
+ break;
+ }ARGEND
+
+ switch(argc){
+ default:
+ return cliError(usage);
+ case 0:
+ vtRLock(lbox.lock);
+ for(lstn = lbox.head; lstn != nil; lstn = lstn->next)
+ consPrint("\t%s\t%s\n", lstn->address, lstn->dir);
+ vtRUnlock(lbox.lock);
+ break;
+ case 1:
+ if(!dflag){
+ if(lstnAlloc(argv[0], flags) == nil)
+ return 0;
+ break;
+ }
+
+ vtLock(lbox.lock);
+ for(lstn = lbox.head; lstn != nil; lstn = lstn->next){
+ if(strcmp(lstn->address, argv[0]) != 0)
+ continue;
+ if(lstn->afd != -1){
+ close(lstn->afd);
+ lstn->afd = -1;
+ }
+ break;
+ }
+ vtUnlock(lbox.lock);
+
+ if(lstn == nil){
+ vtSetError("listen: '%s' not found", argv[0]);
+ return 0;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+int
+lstnInit(void)
+{
+ lbox.lock = vtLockAlloc();
+
+ cliAddCmd("listen", cmdLstn);
+
+ return 1;
+}