182 lines
2.9 KiB
C
182 lines
2.9 KiB
C
#include "stdinc.h"
|
|
|
|
#include "9.h"
|
|
|
|
typedef struct Lstn Lstn;
|
|
struct Lstn {
|
|
int afd;
|
|
int flags;
|
|
char* address;
|
|
char dir[NETPATHLEN];
|
|
|
|
Lstn* next;
|
|
Lstn* prev;
|
|
};
|
|
|
|
static struct {
|
|
RWLock lock;
|
|
|
|
Lstn* head;
|
|
Lstn* tail;
|
|
} lbox;
|
|
|
|
static void
|
|
lstnFree(Lstn* lstn)
|
|
{
|
|
wlock(&lbox.lock);
|
|
if(lstn->prev != nil)
|
|
lstn->prev->next = lstn->next;
|
|
else
|
|
lbox.head = lstn->next;
|
|
if(lstn->next != nil)
|
|
lstn->next->prev = lstn->prev;
|
|
else
|
|
lbox.tail = lstn->prev;
|
|
wunlock(&lbox.lock);
|
|
|
|
if(lstn->afd != -1)
|
|
close(lstn->afd);
|
|
vtfree(lstn->address);
|
|
vtfree(lstn);
|
|
}
|
|
|
|
static void
|
|
lstnListen(void* a)
|
|
{
|
|
Lstn *lstn;
|
|
int dfd, lfd;
|
|
char newdir[NETPATHLEN];
|
|
|
|
threadsetname("listen");
|
|
|
|
lstn = a;
|
|
for(;;){
|
|
if((lfd = listen(lstn->dir, newdir)) < 0){
|
|
fprint(2, "listen: listen '%s': %r", lstn->dir);
|
|
break;
|
|
}
|
|
if((dfd = accept(lfd, newdir)) >= 0)
|
|
conAlloc(dfd, newdir, lstn->flags);
|
|
else
|
|
fprint(2, "listen: accept %s: %r\n", newdir);
|
|
close(lfd);
|
|
}
|
|
lstnFree(lstn);
|
|
}
|
|
|
|
static Lstn*
|
|
lstnAlloc(char* address, int flags)
|
|
{
|
|
int afd;
|
|
Lstn *lstn;
|
|
char dir[NETPATHLEN];
|
|
|
|
wlock(&lbox.lock);
|
|
for(lstn = lbox.head; lstn != nil; lstn = lstn->next){
|
|
if(strcmp(lstn->address, address) != 0)
|
|
continue;
|
|
werrstr("listen: already serving '%s'", address);
|
|
wunlock(&lbox.lock);
|
|
return nil;
|
|
}
|
|
|
|
if((afd = announce(address, dir)) < 0){
|
|
werrstr("listen: announce '%s': %r", address);
|
|
wunlock(&lbox.lock);
|
|
return nil;
|
|
}
|
|
|
|
lstn = vtmallocz(sizeof(Lstn));
|
|
lstn->afd = afd;
|
|
lstn->address = vtstrdup(address);
|
|
lstn->flags = flags;
|
|
memmove(lstn->dir, dir, NETPATHLEN);
|
|
|
|
if(lbox.tail != nil){
|
|
lstn->prev = lbox.tail;
|
|
lbox.tail->next = lstn;
|
|
}
|
|
else{
|
|
lbox.head = lstn;
|
|
lstn->prev = nil;
|
|
}
|
|
lbox.tail = lstn;
|
|
wunlock(&lbox.lock);
|
|
|
|
if(proccreate(lstnListen, lstn, STACK) < 0){
|
|
werrstr("listen: thread '%s': %r", lstn->address);
|
|
lstnFree(lstn);
|
|
return nil;
|
|
}
|
|
|
|
return lstn;
|
|
}
|
|
|
|
static int
|
|
cmdLstn(int argc, char* argv[])
|
|
{
|
|
int dflag, flags;
|
|
Lstn *lstn;
|
|
char *usage = "usage: listen [-dIN] [address]";
|
|
|
|
dflag = 0;
|
|
flags = 0;
|
|
ARGBEGIN{
|
|
default:
|
|
return cliError(usage);
|
|
case 'd':
|
|
dflag = 1;
|
|
break;
|
|
case 'I':
|
|
flags |= ConIPCheck;
|
|
break;
|
|
case 'N':
|
|
flags |= ConNoneAllow;
|
|
break;
|
|
}ARGEND
|
|
|
|
switch(argc){
|
|
default:
|
|
return cliError(usage);
|
|
case 0:
|
|
rlock(&lbox.lock);
|
|
for(lstn = lbox.head; lstn != nil; lstn = lstn->next)
|
|
consPrint("\t%s\t%s\n", lstn->address, lstn->dir);
|
|
runlock(&lbox.lock);
|
|
break;
|
|
case 1:
|
|
if(!dflag){
|
|
if(lstnAlloc(argv[0], flags) == nil)
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
wlock(&lbox.lock);
|
|
for(lstn = lbox.head; lstn != nil; lstn = lstn->next){
|
|
if(strcmp(lstn->address, argv[0]) != 0)
|
|
continue;
|
|
if(lstn->afd != -1){
|
|
close(lstn->afd);
|
|
lstn->afd = -1;
|
|
}
|
|
break;
|
|
}
|
|
wunlock(&lbox.lock);
|
|
|
|
if(lstn == nil){
|
|
werrstr("listen: '%s' not found", argv[0]);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
lstnInit(void)
|
|
{
|
|
cliAddCmd("listen", cmdLstn);
|
|
|
|
return 1;
|
|
}
|