teed.c - teed - A multiplex relay tee(1) daemon. | |
git clone git://bitreich.org/teed git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
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) <… | |
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… | |
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 … | |
296 close(*(int *)qe… | |
297 qe = llist_del(&… | |
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 |