plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

9lstn.c (2979B)


      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 	RWLock	lock;
     18 
     19 	Lstn*	head;
     20 	Lstn*	tail;
     21 } lbox;
     22 
     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);
     36 
     37 	if(lstn->afd != -1)
     38 		close(lstn->afd);
     39 	vtfree(lstn->address);
     40 	vtfree(lstn);
     41 }
     42 
     43 static void
     44 lstnListen(void* a)
     45 {
     46 	Lstn *lstn;
     47 	int dfd, lfd;
     48 	char newdir[NETPATHLEN];
     49 
     50  	threadsetname("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 	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 	}
     82 
     83 	if((afd = announce(address, dir)) < 0){
     84 		werrstr("listen: announce '%s': %r", address);
     85 		wunlock(&lbox.lock);
     86 		return nil;
     87 	}
     88 
     89 	lstn = vtmallocz(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 	wunlock(&lbox.lock);
    105 
    106 	if(proccreate(lstnListen, lstn, STACK) < 0){
    107 		werrstr("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 		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;
    152 		}
    153 
    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;
    161 			}
    162 			break;
    163 		}
    164 		wunlock(&lbox.lock);
    165 
    166 		if(lstn == nil){
    167 			werrstr("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 	cliAddCmd("listen", cmdLstn);
    180 
    181 	return 1;
    182 }