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 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);
37 if(lstn->afd != -1)
38 close(lstn->afd);
39 vtfree(lstn->address);
40 vtfree(lstn);
41 }
43 static void
44 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 else
61 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;
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;
112 return lstn;
115 static int
116 cmdLstn(int argc, char* argv[])
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 }ARGEND
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;
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;
162 break;
164 wunlock(&lbox.lock);
166 if(lstn == nil){
167 werrstr("listen: '%s' not found", argv[0]);
168 return 0;
170 break;
173 return 1;
176 int
177 lstnInit(void)
179 cliAddCmd("listen", cmdLstn);
181 return 1;