xref: /plan9/sys/src/cmd/fossil/9lstn.c (revision e12a987081f10894b49298514b3a97b41db862b0)
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 	VtLock*	lock;
18 
19 	Lstn*	head;
20 	Lstn*	tail;
21 } lbox;
22 
23 static void
lstnFree(Lstn * lstn)24 lstnFree(Lstn* lstn)
25 {
26 	vtLock(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 	vtUnlock(lbox.lock);
36 
37 	if(lstn->afd != -1)
38 		close(lstn->afd);
39 	vtMemFree(lstn->address);
40 	vtMemFree(lstn);
41 }
42 
43 static void
lstnListen(void * a)44 lstnListen(void* a)
45 {
46 	Lstn *lstn;
47 	int dfd, lfd;
48 	char newdir[NETPATHLEN];
49 
50  	vtThreadSetName("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*
lstnAlloc(char * address,int flags)68 lstnAlloc(char* address, int flags)
69 {
70 	int afd;
71 	Lstn *lstn;
72 	char dir[NETPATHLEN];
73 
74 	vtLock(lbox.lock);
75 	for(lstn = lbox.head; lstn != nil; lstn = lstn->next){
76 		if(strcmp(lstn->address, address) != 0)
77 			continue;
78 		vtSetError("listen: already serving '%s'", address);
79 		vtUnlock(lbox.lock);
80 		return nil;
81 	}
82 
83 	if((afd = announce(address, dir)) < 0){
84 		vtSetError("listen: announce '%s': %r", address);
85 		vtUnlock(lbox.lock);
86 		return nil;
87 	}
88 
89 	lstn = vtMemAllocZ(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 	vtUnlock(lbox.lock);
105 
106 	if(vtThread(lstnListen, lstn) < 0){
107 		vtSetError("listen: thread '%s': %r", lstn->address);
108 		lstnFree(lstn);
109 		return nil;
110 	}
111 
112 	return lstn;
113 }
114 
115 static int
cmdLstn(int argc,char * argv[])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 		vtRLock(lbox.lock);
143 		for(lstn = lbox.head; lstn != nil; lstn = lstn->next)
144 			consPrint("\t%s\t%s\n", lstn->address, lstn->dir);
145 		vtRUnlock(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 		vtLock(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 		vtUnlock(lbox.lock);
165 
166 		if(lstn == nil){
167 			vtSetError("listen: '%s' not found", argv[0]);
168 			return 0;
169 		}
170 		break;
171 	}
172 
173 	return 1;
174 }
175 
176 int
lstnInit(void)177 lstnInit(void)
178 {
179 	lbox.lock = vtLockAlloc();
180 
181 	cliAddCmd("listen", cmdLstn);
182 
183 	return 1;
184 }
185