Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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*
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
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
177
lstnInit(void)
178
{
179
	lbox.lock = vtLockAlloc();
180
 
181
	cliAddCmd("listen", cmdLstn);
182
 
183
	return 1;
184
}