9lstn.c (2979B)
1 #include "stdinc.h" 2 3 #include "9.h" 4 5 typedef struct Lstn Lstn; 6 struct Lstn { 7 int afd; 8 int flags; 9 char* address; 10 char dir[NETPATHLEN]; 11 12 Lstn* next; 13 Lstn* prev; 14 }; 15 16 static struct { 17 RWLock lock; 18 19 Lstn* head; 20 Lstn* tail; 21 } lbox; 22 23 static void 24 lstnFree(Lstn* lstn) 25 { 26 wlock(&lbox.lock); 27 if(lstn->prev != nil) 28 lstn->prev->next = lstn->next; 29 else 30 lbox.head = lstn->next; 31 if(lstn->next != nil) 32 lstn->next->prev = lstn->prev; 33 else 34 lbox.tail = lstn->prev; 35 wunlock(&lbox.lock); 36 37 if(lstn->afd != -1) 38 close(lstn->afd); 39 vtfree(lstn->address); 40 vtfree(lstn); 41 } 42 43 static void 44 lstnListen(void* a) 45 { 46 Lstn *lstn; 47 int dfd, lfd; 48 char newdir[NETPATHLEN]; 49 50 threadsetname("listen"); 51 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 else 61 fprint(2, "listen: accept %s: %r\n", newdir); 62 close(lfd); 63 } 64 lstnFree(lstn); 65 } 66 67 static Lstn* 68 lstnAlloc(char* address, int flags) 69 { 70 int afd; 71 Lstn *lstn; 72 char dir[NETPATHLEN]; 73 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 } 82 83 if((afd = announce(address, dir)) < 0){ 84 werrstr("listen: announce '%s': %r", address); 85 wunlock(&lbox.lock); 86 return nil; 87 } 88 89 lstn = vtmallocz(sizeof(Lstn)); 90 lstn->afd = afd; 91 lstn->address = vtstrdup(address); 92 lstn->flags = flags; 93 memmove(lstn->dir, dir, NETPATHLEN); 94 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); 105 106 if(proccreate(lstnListen, lstn, STACK) < 0){ 107 werrstr("listen: thread '%s': %r", lstn->address); 108 lstnFree(lstn); 109 return nil; 110 } 111 112 return lstn; 113 } 114 115 static int 116 cmdLstn(int argc, char* argv[]) 117 { 118 int dflag, flags; 119 Lstn *lstn; 120 char *usage = "usage: listen [-dIN] [address]"; 121 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 }ARGEND 137 138 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 } 153 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); 165 166 if(lstn == nil){ 167 werrstr("listen: '%s' not found", argv[0]); 168 return 0; 169 } 170 break; 171 } 172 173 return 1; 174 } 175 176 int 177 lstnInit(void) 178 { 179 cliAddCmd("listen", cmdLstn); 180 181 return 1; 182 }