blob: 9ba508f422f6cb6b6cbd7d5f0c076200666fc65a [file] [log] [blame]
#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 {
VtLock* lock;
Lstn* head;
Lstn* tail;
} lbox;
static void
lstnFree(Lstn* lstn)
{
vtLock(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;
vtUnlock(lbox.lock);
if(lstn->afd != -1)
close(lstn->afd);
vtMemFree(lstn->address);
vtMemFree(lstn);
}
static void
lstnListen(void* a)
{
Lstn *lstn;
int dfd, lfd;
char newdir[NETPATHLEN];
vtThreadSetName("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];
vtLock(lbox.lock);
for(lstn = lbox.head; lstn != nil; lstn = lstn->next){
if(strcmp(lstn->address, address) != 0)
continue;
vtSetError("listen: already serving '%s'", address);
vtUnlock(lbox.lock);
return nil;
}
if((afd = announce(address, dir)) < 0){
vtSetError("listen: announce '%s': %r", address);
vtUnlock(lbox.lock);
return nil;
}
lstn = vtMemAllocZ(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;
vtUnlock(lbox.lock);
if(vtThread(lstnListen, lstn) < 0){
vtSetError("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:
vtRLock(lbox.lock);
for(lstn = lbox.head; lstn != nil; lstn = lstn->next)
consPrint("\t%s\t%s\n", lstn->address, lstn->dir);
vtRUnlock(lbox.lock);
break;
case 1:
if(!dflag){
if(lstnAlloc(argv[0], flags) == nil)
return 0;
break;
}
vtLock(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;
}
vtUnlock(lbox.lock);
if(lstn == nil){
vtSetError("listen: '%s' not found", argv[0]);
return 0;
}
break;
}
return 1;
}
int
lstnInit(void)
{
lbox.lock = vtLockAlloc();
cliAddCmd("listen", cmdLstn);
return 1;
}