Home
       teed.c - teed - A multiplex relay tee(1) daemon.
  HTML git clone git://bitreich.org/teed git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/teed
   DIR Log
   DIR Files
   DIR Refs
   DIR Tags
   DIR README
   DIR LICENSE
       ---
       teed.c (5223B)
       ---
            1 /*
            2  * See LICENSE file for license information.
            3  *
            4  * Copy me if you can.
            5  * by 20h
            6  */
            7 
            8 #include <unistd.h>
            9 #include <stdio.h>
           10 #include <stdlib.h>
           11 #include <string.h>
           12 #include <sys/socket.h>
           13 #include <sys/un.h>
           14 #include <signal.h>
           15 #include <errno.h>
           16 #include <sys/stat.h>
           17 #include <sys/select.h>
           18 
           19 volatile sig_atomic_t isrunning = 1;
           20 
           21 void *
           22 memdup(void *p, int l)
           23 {
           24         char *ret;
           25 
           26         ret = calloc(1, l);
           27         if (ret == NULL) {
           28                 perror("calloc");
           29                 exit(1);
           30         }
           31         memcpy(ret, p, l);
           32 
           33         return (void *)ret;
           34 }
           35 
           36 typedef struct llist llist;
           37 struct llist {
           38         llist *prev;
           39         llist *next;
           40         int dlen;
           41         void *data;
           42 };
           43 
           44 #define forllist(list, elem) for (elem = list;\
           45                 elem; elem = elem->next)
           46 
           47 void
           48 closeallfds(llist *fds)
           49 {
           50         llist *e;
           51 
           52         forllist(fds, e)
           53                 close(*(int *)e->data);
           54 }
           55 
           56 void
           57 llist_free1(llist *l)
           58 {
           59         if (l == NULL)
           60                 return;
           61         free(l->data);
           62         l->data = NULL;
           63         l->next = NULL;
           64         l->prev = NULL;
           65         free(l);
           66 }
           67 
           68 void
           69 llist_free(llist *l)
           70 {
           71         llist *tl;
           72 
           73         while (l != NULL) {
           74                 tl = l->next;
           75                 llist_free1(l);
           76                 l = tl;
           77         }
           78 }
           79 
           80 llist *
           81 llist_new(llist *prev, llist *next, void *data, int len)
           82 {
           83         llist *ret;
           84 
           85         ret = calloc(1, sizeof(llist));
           86         if (ret == NULL) {
           87                 perror("calloc");
           88                 exit(1);
           89         }
           90         ret->prev = prev;
           91         ret->next = next;
           92         if (data != NULL) {
           93                 ret->data = memdup(data, len);
           94                 ret->dlen = len;
           95         } else {
           96                 ret->data = NULL;
           97                 ret->dlen = 0;
           98         }
           99 
          100         return ret;
          101 }
          102 
          103 int
          104 llist_len(llist *l)
          105 {
          106         int llistl = 0;
          107         for (;l != NULL; l = l->next)
          108                 llistl++;
          109         return llistl;
          110 }
          111 
          112 llist *
          113 llist_put(llist *l, void *data, int len)
          114 {
          115         llist *ol;
          116 
          117         if (l == NULL)
          118                 return llist_new(NULL, NULL, data, len);
          119 
          120         ol = l;
          121         for (; l->next; l = l->next);
          122         l->next = llist_new(l, NULL, data, len);
          123 
          124         return ol;
          125 }
          126 
          127 llist *
          128 llist_del(llist **l, llist *e)
          129 {
          130         llist *enext, *eprev;
          131 
          132         enext = e->next;
          133         eprev = e->prev;
          134         if (enext != NULL)
          135                 enext->prev = eprev;
          136         if (eprev != NULL)
          137                 eprev->next = enext;
          138         llist_free1(e);
          139 
          140         if (*l == e)
          141                 *l = enext;
          142 
          143         if (eprev != NULL)
          144                 return eprev;
          145         if (enext != NULL)
          146                 return enext;
          147         return NULL;
          148 }
          149 
          150 void
          151 sighandler(int signo)
          152 {
          153         switch (signo) {
          154         case SIGINT:
          155         case SIGTERM:
          156                 isrunning = 0;
          157                 break;
          158         }
          159 }
          160 
          161 void
          162 initsignals(void)
          163 {
          164         signal(SIGPIPE, SIG_IGN);
          165         signal(SIGINT, sighandler);
          166         signal(SIGTERM, sighandler);
          167 }
          168 
          169 int
          170 main(int argc, char *argv[])
          171 {
          172         int on, i, maxsfd, afd, rval, recvl,
          173             sendl, sent, lfd;
          174         struct sockaddr_un saddrs[2], clt;
          175         char *bindpaths[2] = {"in", "out"},
          176              recvbuf[4*1024],
          177              *sendbufi;
          178         llist *wfds, *rfds, *lfds, *e, *qe;
          179         socklen_t saddrlen, cltlen;
          180         fd_set fdset;
          181         struct timespec timeout;
          182 
          183         initsignals();
          184 
          185         rval = 1;
          186         rfds = NULL;
          187         wfds = NULL;
          188         lfds = NULL;
          189 
          190         on = 1;
          191         for (i = 0; i < 2; i++) {
          192                 lfd = socket(AF_UNIX, SOCK_STREAM, 0);
          193                 if (lfd < 0) {
          194                         perror("socket");
          195                         goto stop_serving;
          196                 }
          197                 if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR,
          198                                 &on, sizeof(on)) < 0) {
          199                         perror("setsockopt");
          200                         goto stop_serving;
          201                 }
          202 
          203                 if (access(bindpaths[i], F_OK) == 0) {
          204                         if (remove(bindpaths[i]) < 0) {
          205                                 perror("remove");
          206                                 goto stop_serving;
          207                         }
          208                 }
          209 
          210                 saddrs[i].sun_family = AF_UNIX;
          211                 strncpy(saddrs[i].sun_path, bindpaths[i],
          212                         sizeof(bindpaths[i])-1);
          213                 saddrlen = sizeof(saddrs[i]);
          214 
          215                 if (bind(lfd, (struct sockaddr *)&saddrs[i], saddrlen) < 0) {
          216                         perror("bind");
          217                         goto stop_serving;
          218                 }
          219 
          220                 if (chmod(bindpaths[i], 0775) < 0) {
          221                         perror("chmod");
          222                         goto stop_serving;
          223                 }
          224 
          225                 if (listen(lfd, 255) < 0) {
          226                         perror("listen");
          227                         goto stop_serving;
          228                 }
          229 
          230                 lfds = llist_put(lfds, &lfd, sizeof(lfd));
          231         }
          232 
          233         timeout.tv_sec = 1;
          234         timeout.tv_nsec = 0;
          235         for (;isrunning;) {
          236                 maxsfd = 0;
          237                 FD_ZERO(&fdset);
          238                 forllist(lfds, e) {
          239                         FD_SET(*(int *)e->data, &fdset);
          240                         if (*(int *)e->data > maxsfd)
          241                                 maxsfd = *(int *)e->data;
          242                 }
          243                 forllist(rfds, e) {
          244                         FD_SET(*(int *)e->data, &fdset);
          245                         if (*(int *)e->data > maxsfd)
          246                                 maxsfd = *(int *)e->data;
          247                 }
          248 
          249                 if (pselect(maxsfd+1, &fdset, NULL, NULL, &timeout, NULL) < 0) {
          250                         if (errno == EINTR)
          251                                 continue;
          252                         perror("pselect");
          253                         goto stop_serving;
          254                 }
          255 
          256                 i = -1;
          257                 forllist(lfds, e) {
          258                         i++;
          259                         if (FD_ISSET(*(int *)e->data, &fdset)) {
          260                                 cltlen = sizeof(clt);
          261                                 afd = accept(*(int *)e->data,
          262                                         (struct sockaddr *)&clt,
          263                                         &cltlen);
          264                                 if (afd < 0 && errno != ECONNABORTED
          265                                             && errno != EINTR) {
          266                                         perror("accept");
          267                                         goto stop_serving;
          268                                 }
          269 
          270                                 if (i == 0) {
          271                                         rfds = llist_put(rfds, &afd,
          272                                                         sizeof(afd));
          273                                 } else {
          274                                         wfds = llist_put(wfds, &afd,
          275                                                         sizeof(afd));
          276                                 }
          277                         }
          278                 }
          279 
          280                 forllist(rfds, e) {
          281                         if (FD_ISSET(*(int *)e->data, &fdset)) {
          282                                 recvl = read(*(int *)e->data, recvbuf,
          283                                                 sizeof(recvbuf));
          284                                 if (recvl <= 0) {
          285                                         close(*(int *)e->data);
          286                                         e = llist_del(&rfds, e);
          287                                         if (e == NULL)
          288                                                 break;
          289                                 }
          290 
          291                                 forllist(wfds, qe) {
          292                                         sendbufi = recvbuf;
          293                                         sendl = recvl;
          294                                         while (sendl > 0) {
          295                                                 if ((sent = write(*(int *)qe->data, sendbufi, sendl)) < 0) {
          296                                                         close(*(int *)qe->data);
          297                                                         qe = llist_del(&wfds, qe);
          298                                                         break;
          299                                                 }
          300                                                 sendl -= sent;
          301                                                 sendbufi += sent;
          302                                         }
          303                                         if (qe == NULL)
          304                                                 break;
          305                                 }
          306                         }
          307                 }
          308 
          309         }
          310 
          311         rval = 0;
          312 stop_serving:
          313         closeallfds(lfds);
          314         llist_free(lfds);
          315         closeallfds(rfds);
          316         llist_free(rfds);
          317         closeallfds(wfds);
          318         llist_free(wfds);
          319 
          320         return rval;
          321 }
          322