9lstn.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #include "stdinc.h"
  2. #include "9.h"
  3. typedef struct Lstn Lstn;
  4. typedef struct Lstn {
  5. int afd;
  6. char* address;
  7. char dir[NETPATHLEN];
  8. Lstn* next;
  9. Lstn* prev;
  10. } Lstn;
  11. static struct {
  12. VtLock* lock;
  13. Lstn* head;
  14. Lstn* tail;
  15. } lbox;
  16. static void
  17. lstnFree(Lstn* lstn)
  18. {
  19. vtLock(lbox.lock);
  20. if(lstn->prev != nil)
  21. lstn->prev->next = lstn->next;
  22. else
  23. lbox.head = lstn->next;
  24. if(lstn->next != nil)
  25. lstn->next->prev = lstn->prev;
  26. else
  27. lbox.tail = lstn->prev;
  28. vtUnlock(lbox.lock);
  29. if(lstn->afd != -1)
  30. close(lstn->afd);
  31. vtMemFree(lstn->address);
  32. vtMemFree(lstn);
  33. }
  34. static void
  35. lstnListen(void* a)
  36. {
  37. Lstn *lstn;
  38. int dfd, lfd;
  39. char newdir[NETPATHLEN];
  40. vtThreadSetName("listen");
  41. lstn = a;
  42. for(;;){
  43. if((lfd = listen(lstn->dir, newdir)) < 0){
  44. fprint(2, "listen: listen '%s': %r", lstn->dir);
  45. break;
  46. }
  47. if((dfd = accept(lfd, newdir)) >= 0)
  48. conAlloc(dfd, newdir);
  49. else
  50. fprint(2, "listen: accept '%s': %r", newdir);
  51. close(lfd);
  52. }
  53. lstnFree(lstn);
  54. }
  55. static Lstn*
  56. lstnAlloc(char* address)
  57. {
  58. int afd;
  59. Lstn *lstn;
  60. char dir[NETPATHLEN];
  61. vtLock(lbox.lock);
  62. for(lstn = lbox.head; lstn != nil; lstn = lstn->next){
  63. if(strcmp(lstn->address, address) != 0)
  64. continue;
  65. vtSetError("listen: already serving '%s'", address);
  66. vtUnlock(lbox.lock);
  67. return nil;
  68. }
  69. if((afd = announce(address, dir)) < 0){
  70. vtSetError("listen: announce '%s': %r", address);
  71. vtUnlock(lbox.lock);
  72. return nil;
  73. }
  74. lstn = vtMemAllocZ(sizeof(Lstn));
  75. lstn->afd = afd;
  76. lstn->address = vtStrDup(address);
  77. memmove(lstn->dir, dir, NETPATHLEN);
  78. if(lbox.tail != nil){
  79. lstn->prev = lbox.tail;
  80. lbox.tail->next = lstn;
  81. }
  82. else{
  83. lbox.head = lstn;
  84. lstn->prev = nil;
  85. }
  86. lbox.tail = lstn;
  87. vtUnlock(lbox.lock);
  88. if(vtThread(lstnListen, lstn) < 0){
  89. vtSetError("listen: thread '%s': %r", lstn->address);
  90. lstnFree(lstn);
  91. return nil;
  92. }
  93. return lstn;
  94. }
  95. static int
  96. cmdLstn(int argc, char* argv[])
  97. {
  98. int dflag;
  99. Lstn *lstn;
  100. char *usage = "usage: listen [-d] [address]";
  101. dflag = 0;
  102. ARGBEGIN{
  103. default:
  104. return cliError(usage);
  105. case 'd':
  106. dflag = 1;
  107. break;
  108. }ARGEND
  109. switch(argc){
  110. default:
  111. return cliError(usage);
  112. case 0:
  113. vtRLock(lbox.lock);
  114. for(lstn = lbox.head; lstn != nil; lstn = lstn->next)
  115. consPrint("\t%s\t%s\n", lstn->address, lstn->dir);
  116. vtRUnlock(lbox.lock);
  117. break;
  118. case 1:
  119. if(!dflag){
  120. if(lstnAlloc(argv[0]) == nil)
  121. return 0;
  122. break;
  123. }
  124. vtLock(lbox.lock);
  125. for(lstn = lbox.head; lstn != nil; lstn = lstn->next){
  126. if(strcmp(lstn->address, argv[0]) != 0)
  127. continue;
  128. if(lstn->afd != -1){
  129. close(lstn->afd);
  130. lstn->afd = -1;
  131. }
  132. break;
  133. }
  134. vtUnlock(lbox.lock);
  135. if(lstn == nil){
  136. vtSetError("listen: '%s' not found", argv[0]);
  137. return 0;
  138. }
  139. break;
  140. }
  141. return 1;
  142. }
  143. int
  144. lstnInit(void)
  145. {
  146. lbox.lock = vtLockAlloc();
  147. cliAddCmd("listen", cmdLstn);
  148. return 1;
  149. }