Blob
1 #include "stdinc.h"3 #include "9.h"5 typedef struct Lstn Lstn;6 struct Lstn {7 int afd;8 int flags;9 char* address;10 char dir[NETPATHLEN];12 Lstn* next;13 Lstn* prev;14 };16 static struct {17 RWLock lock;19 Lstn* head;20 Lstn* tail;21 } lbox;23 static void24 lstnFree(Lstn* lstn)25 {26 wlock(&lbox.lock);27 if(lstn->prev != nil)28 lstn->prev->next = lstn->next;29 else30 lbox.head = lstn->next;31 if(lstn->next != nil)32 lstn->next->prev = lstn->prev;33 else34 lbox.tail = lstn->prev;35 wunlock(&lbox.lock);37 if(lstn->afd != -1)38 close(lstn->afd);39 vtfree(lstn->address);40 vtfree(lstn);41 }43 static void44 lstnListen(void* a)45 {46 Lstn *lstn;47 int dfd, lfd;48 char newdir[NETPATHLEN];50 threadsetname("listen");52 lstn = a;53 for(;;){54 if((lfd = listen(lstn->dir, newdir)) < 0){55 fprint(2, "listen: listen '%s': %r", lstn->dir);56 break;57 }58 if((dfd = accept(lfd, newdir)) >= 0)59 conAlloc(dfd, newdir, lstn->flags);60 else61 fprint(2, "listen: accept %s: %r\n", newdir);62 close(lfd);63 }64 lstnFree(lstn);65 }67 static Lstn*68 lstnAlloc(char* address, int flags)69 {70 int afd;71 Lstn *lstn;72 char dir[NETPATHLEN];74 wlock(&lbox.lock);75 for(lstn = lbox.head; lstn != nil; lstn = lstn->next){76 if(strcmp(lstn->address, address) != 0)77 continue;78 werrstr("listen: already serving '%s'", address);79 wunlock(&lbox.lock);80 return nil;81 }83 if((afd = announce(address, dir)) < 0){84 werrstr("listen: announce '%s': %r", address);85 wunlock(&lbox.lock);86 return nil;87 }89 lstn = vtmallocz(sizeof(Lstn));90 lstn->afd = afd;91 lstn->address = vtstrdup(address);92 lstn->flags = flags;93 memmove(lstn->dir, dir, NETPATHLEN);95 if(lbox.tail != nil){96 lstn->prev = lbox.tail;97 lbox.tail->next = lstn;98 }99 else{100 lbox.head = lstn;101 lstn->prev = nil;102 }103 lbox.tail = lstn;104 wunlock(&lbox.lock);106 if(proccreate(lstnListen, lstn, STACK) < 0){107 werrstr("listen: thread '%s': %r", lstn->address);108 lstnFree(lstn);109 return nil;110 }112 return lstn;113 }115 static int116 cmdLstn(int argc, char* argv[])117 {118 int dflag, flags;119 Lstn *lstn;120 char *usage = "usage: listen [-dIN] [address]";122 dflag = 0;123 flags = 0;124 ARGBEGIN{125 default:126 return cliError(usage);127 case 'd':128 dflag = 1;129 break;130 case 'I':131 flags |= ConIPCheck;132 break;133 case 'N':134 flags |= ConNoneAllow;135 break;136 }ARGEND138 switch(argc){139 default:140 return cliError(usage);141 case 0:142 rlock(&lbox.lock);143 for(lstn = lbox.head; lstn != nil; lstn = lstn->next)144 consPrint("\t%s\t%s\n", lstn->address, lstn->dir);145 runlock(&lbox.lock);146 break;147 case 1:148 if(!dflag){149 if(lstnAlloc(argv[0], flags) == nil)150 return 0;151 break;152 }154 wlock(&lbox.lock);155 for(lstn = lbox.head; lstn != nil; lstn = lstn->next){156 if(strcmp(lstn->address, argv[0]) != 0)157 continue;158 if(lstn->afd != -1){159 close(lstn->afd);160 lstn->afd = -1;161 }162 break;163 }164 wunlock(&lbox.lock);166 if(lstn == nil){167 werrstr("listen: '%s' not found", argv[0]);168 return 0;169 }170 break;171 }173 return 1;174 }176 int177 lstnInit(void)178 {179 cliAddCmd("listen", cmdLstn);181 return 1;182 }