1 /*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25 /**@internal @ingroup su_root_ex
26 *
27 * @file su_proxy.c
28 *
29 * @brief Transport level proxy demonstrating various @b su features.
30 *
31 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
32 *
33 * @date Created: Wed May 23 17:42:40 2001 ppessi
34 */
35
36 #include "config.h"
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stddef.h>
42 #include <errno.h>
43
44 #include <assert.h>
45
46 typedef struct proxy_s proxy_t;
47 typedef struct forwarder_s forwarder_t;
48 typedef struct buffer_s buffer_t;
49
50 #define SU_ROOT_MAGIC_T proxy_t
51 #define SU_MSG_ARG_T su_socket_t
52 #define SU_WAKEUP_ARG_T forwarder_t
53
54 #include "sofia-sip/su.h"
55 #include "sofia-sip/su_wait.h"
56 #include "sofia-sip/su_alloc.h"
57 #include "su_module_debug.h"
58
59 #if HAVE_FUNC
60 #elif HAVE_FUNCTION
61 #define __func__ __FUNCTION__
62 #else
63 #define __func__ "su_proxy"
64 #endif
65
66 struct proxy_s
67 {
68 su_home_t pr_home[1];
69 su_root_t *pr_root;
70 su_addrinfo_t *pr_addrinfo;
71 forwarder_t *pr_forwarders;
72 };
73
74 struct forwarder_s
75 {
76 forwarder_t *f_next;
77 forwarder_t **f_prev;
78 proxy_t *f_pr;
79 su_socket_t f_socket;
80 su_wait_t f_wait[2];
81 forwarder_t *f_peer;
82 su_sockaddr_t f_dest[1];
83 buffer_t *f_buf;
84 unsigned long f_sent; /* bytes sent */
85 unsigned f_shutdown : 1;
86 unsigned f_upstream : 1;
87 };
88
89 struct buffer_s
90 {
91 buffer_t *b_next;
92 buffer_t **b_prev;
93 int b_sent;
94 int b_used;
95 char b_data[8192];
96 };
97
98 char const help[] =
99 "usage: su_proxy [-ntu] remotehost remoteport [localport]\n";
100
usage(void)101 void usage(void)
102 {
103 fputs(help, stderr);
104 }
105
106 static int pr_init(proxy_t *pr);
107 static int pr_config(proxy_t *pr, int argc, char *argv[]);
108 static int pr_run(proxy_t *pr);
109 static void pr_deinit(proxy_t *pr);
110
111 static forwarder_t *forwarder_create(proxy_t *pr);
112 static forwarder_t *forwarder_create_listener(proxy_t *pr, su_addrinfo_t *ai);
113 static void forwarder_deinit(forwarder_t *f);
114 static int forwarder_init_stream(forwarder_t *f);
115 static int forwarder_init_dgram(forwarder_t *f);
116 static int forwarder_accept(proxy_t *pr, su_wait_t *w, forwarder_t *f);
117 static int forwarder_stream_peer(proxy_t *pr, forwarder_t *f);
118 static int forwarder_connected(proxy_t *pr, su_wait_t *w, forwarder_t *f);
119 static int forwarder_recv(proxy_t *pr, su_wait_t *w, forwarder_t *f);
120 static int forwarder_send(proxy_t *pr, forwarder_t *f, buffer_t *b);
121 static int forwarder_append(forwarder_t *f, buffer_t *b0);
122 static int forwarder_empty(proxy_t *pr, su_wait_t *w, forwarder_t *f);
123 static int forwarder_shutdown(forwarder_t *f);
124 static void forwarder_close(forwarder_t *f1);
125
main(int argc,char * argv[])126 int main(int argc, char *argv[])
127 {
128 proxy_t pr[1] = {{{ SU_HOME_INIT(pr) }}};
129 int error;
130
131 error = pr_init(pr);
132 if (error == 0) {
133 if ((error = pr_config(pr, argc, argv)) > 1)
134 usage();
135 }
136
137 if (error == 0)
138 error = pr_run(pr);
139
140 pr_deinit(pr);
141
142 su_deinit();
143
144 exit(error);
145 }
146
pr_init(proxy_t * pr)147 int pr_init(proxy_t *pr)
148 {
149 su_init();
150 su_home_init(pr->pr_home);
151 pr->pr_root = su_root_create(pr);
152 return pr->pr_root ? 0 : 1;
153 }
154
pr_config(proxy_t * pr,int argc,char * argv[])155 int pr_config(proxy_t *pr, int argc, char *argv[])
156 {
157 su_addrinfo_t *res = NULL, *ai, hints[1] = {{ 0 }};
158 char *service;
159 int error;
160 char const *option;
161
162 /* char const *argv0 = argv[0]; */
163
164 while (argv[1][0] == '-') {
165 option = argv[1];
166 argv++, argc--;
167 if (strcmp(option, "--") == 0)
168 break;
169 else if (strcmp(option, "-n") == 0) {
170 hints->ai_flags |= AI_NUMERICHOST;
171 }
172 else if (strcmp(option, "-d") == 0) {
173 hints->ai_socktype = SOCK_DGRAM;
174 }
175 else if (strcmp(option, "-s") == 0) {
176 hints->ai_socktype = SOCK_STREAM;
177 }
178 else if (strcmp(option, "-4") == 0) {
179 hints->ai_family = AF_INET;
180 }
181 #if SU_HAVE_IN6
182 else if (strcmp(option, "-6") == 0) {
183 hints->ai_family = AF_INET6;
184 }
185 #endif
186 }
187
188 if (argc < 3)
189 return 2;
190
191 if ((error = su_getaddrinfo(argv[1], argv[2], hints, &res))) {
192 fprintf(stderr, "getaddrinfo: %s:%s: %s\n",
193 argv[1], argv[2], su_gai_strerror(error));
194 return 1;
195 }
196
197 pr->pr_addrinfo = res;
198
199 if (argv[3])
200 service = argv[3];
201 else
202 service = argv[2];
203
204 hints->ai_flags |= AI_PASSIVE;
205
206 if ((error = su_getaddrinfo(NULL, service, hints, &res))) {
207 fprintf(stderr, "getaddrinfo: %s: %s\n", service, su_gai_strerror(error));
208 return 1;
209 }
210
211 for (ai = res;
212 ai;
213 ai = ai->ai_next) {
214 forwarder_create_listener(pr, ai);
215 }
216
217 su_freeaddrinfo(res);
218
219 if (!pr->pr_forwarders) {
220 fprintf(stderr, "%s:%s: %s\n", argv[1], argv[2], "unable to forward");
221 return 1;
222 }
223
224 return 0;
225 }
226
pr_deinit(proxy_t * pr)227 void pr_deinit(proxy_t *pr)
228 {
229 if (pr->pr_addrinfo)
230 su_freeaddrinfo(pr->pr_addrinfo), pr->pr_addrinfo = NULL;
231
232 if (pr->pr_root)
233 su_root_destroy(pr->pr_root), pr->pr_root = NULL;
234
235 su_home_deinit(pr->pr_home);
236
237 su_deinit();
238 }
239
pr_run(proxy_t * pr)240 static int pr_run(proxy_t *pr)
241 {
242 su_root_run(pr->pr_root);
243
244 return 0;
245 }
246
forwarder_create(proxy_t * pr)247 forwarder_t *forwarder_create(proxy_t *pr)
248 {
249 forwarder_t *f;
250
251 assert(pr);
252
253 f = su_zalloc(pr->pr_home, sizeof (*f));
254
255 if (f) {
256 f->f_socket = INVALID_SOCKET;
257 su_wait_init(f->f_wait);
258 su_wait_init(f->f_wait + 1);
259 f->f_pr = pr;
260 if ((f->f_next = pr->pr_forwarders))
261 f->f_next->f_prev = &f->f_next;
262 f->f_prev = &pr->pr_forwarders;
263 pr->pr_forwarders = f;
264 }
265
266 return f;
267 }
268
forwarder_destroy(forwarder_t * f)269 void forwarder_destroy(forwarder_t *f)
270 {
271 if (f) {
272 forwarder_deinit(f);
273
274 if (f->f_peer) {
275 f->f_peer->f_peer = NULL;
276 forwarder_destroy(f->f_peer);
277 f->f_peer = NULL;
278 }
279 assert(f->f_prev);
280
281 if ((*f->f_prev = f->f_next))
282 f->f_next->f_prev = f->f_prev;
283
284 su_free(f->f_pr->pr_home, f);
285 }
286 }
287
forwarder_deinit(forwarder_t * f)288 void forwarder_deinit(forwarder_t *f)
289 {
290 su_root_unregister(f->f_pr->pr_root, f->f_wait, NULL, f);
291 su_wait_destroy(f->f_wait);
292 su_root_unregister(f->f_pr->pr_root, f->f_wait + 1, NULL, f);
293 su_wait_destroy(f->f_wait + 1);
294 if (f->f_socket != INVALID_SOCKET)
295 su_close(f->f_socket), f->f_socket = INVALID_SOCKET;
296 if (f->f_buf)
297 su_free(f->f_pr->pr_home, f->f_buf), f->f_buf = NULL;
298 }
299
forwarder_create_listener(proxy_t * pr,su_addrinfo_t * ai)300 static forwarder_t *forwarder_create_listener(proxy_t *pr, su_addrinfo_t *ai)
301 {
302 forwarder_t *f;
303 su_socket_t s;
304
305 if (ai->ai_socktype != SOCK_STREAM &&
306 ai->ai_socktype != SOCK_DGRAM)
307 return NULL;
308
309 f = forwarder_create(pr);
310
311 if (f) {
312 s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
313 if (s != INVALID_SOCKET) {
314 f->f_socket = s;
315 su_setblocking(s, 0);
316 su_setreuseaddr(s, 1);
317 if (bind(s, ai->ai_addr, ai->ai_addrlen) >= 0) {
318 if (ai->ai_socktype == SOCK_STREAM ?
319 forwarder_init_stream(f) >= 0 :
320 forwarder_init_dgram(f) >= 0)
321 return f;
322 }
323 else {
324 SU_DEBUG_1(("%s: bind: %s\n", __func__, su_strerror(su_errno())));
325 }
326 }
327 }
328
329 forwarder_destroy(f);
330
331 return NULL;
332 }
333
forwarder_init_stream(forwarder_t * f)334 int forwarder_init_stream(forwarder_t *f)
335 {
336 if (listen(f->f_socket, SOMAXCONN) < 0)
337 return SOCKET_ERROR;
338
339 if (su_wait_create(f->f_wait, f->f_socket, SU_WAIT_ACCEPT) < 0)
340 return SOCKET_ERROR;
341
342 if (su_root_register(f->f_pr->pr_root, f->f_wait,
343 forwarder_accept, f, 0) < 0)
344 return SOCKET_ERROR;
345
346 return 0;
347 }
348
forwarder_init_dgram(forwarder_t * f)349 int forwarder_init_dgram(forwarder_t *f)
350 {
351 /* Unimplemented */
352 return SOCKET_ERROR;
353 }
354
355 /** Accept a connection. */
forwarder_accept(proxy_t * pr,su_wait_t * w,forwarder_t * f0)356 int forwarder_accept(proxy_t *pr, su_wait_t *w, forwarder_t *f0)
357 {
358 forwarder_t *f;
359 su_sockaddr_t *su;
360 socklen_t sulen;
361 int events;
362
363 events = su_wait_events(w, f0->f_socket);
364
365 f = forwarder_create(pr);
366
367 if (f) {
368 su = f->f_dest;
369 sulen = sizeof(f->f_dest);
370 f->f_socket = accept(f0->f_socket, &su->su_sa, &sulen);
371 f->f_upstream = 1;
372 if (f->f_socket != INVALID_SOCKET) {
373 char buf[SU_ADDRSIZE];
374
375 SU_DEBUG_3(("accept: connection from %s:%u\n",
376 su_inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
377 ntohs(su->su_port)));
378
379 if (!su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) &&
380 !su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) {
381 if (forwarder_stream_peer(pr, f) != SOCKET_ERROR) {
382 /* success */
383 return 0;
384 }
385 }
386 else {
387 SU_DEBUG_1(("%s: cannot create wait objects\n", __func__));
388 }
389 }
390 }
391
392 forwarder_destroy(f);
393
394 return 0;
395 }
396
forwarder_stream_peer(proxy_t * pr,forwarder_t * f_peer)397 int forwarder_stream_peer(proxy_t *pr, forwarder_t *f_peer)
398 {
399 forwarder_t *f;
400 su_addrinfo_t *ai;
401
402 assert(f_peer);
403
404 f = forwarder_create(pr);
405 if (!f) {
406 SU_DEBUG_1(("%s: cannot allocate peer\n", __func__));
407 goto error;
408 }
409
410 for (ai = pr->pr_addrinfo; ai; ai = ai->ai_next) {
411 if (ai->ai_socktype == SOCK_STREAM)
412 break;
413 }
414
415 if (!ai) {
416 SU_DEBUG_1(("%s: no matching destination\n", __func__));
417 goto error;
418 }
419
420 f->f_socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
421 if (f->f_socket == INVALID_SOCKET) {
422 SU_DEBUG_1(("%s: socket: %s\n", __func__, su_strerror(su_errno())));
423 goto error;
424 }
425
426 if (su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) ||
427 su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) {
428 SU_DEBUG_1(("%s: cannot create wait objects\n", __func__));
429 goto error;
430 }
431
432 /* Asynchronous connect */
433 su_setblocking(f->f_socket, 0);
434 su_seterrno(0);
435 connect(f->f_socket, ai->ai_addr, ai->ai_addrlen);
436 memcpy(f->f_dest, ai->ai_addr, ai->ai_addrlen);
437
438 if (su_errno() != EINPROGRESS) {
439 SU_DEBUG_1(("%s: connect: %s\n", __func__, su_strerror(su_errno())));
440 goto error;
441 }
442
443 if (su_root_register(pr->pr_root, f->f_wait + 1,
444 forwarder_connected, f, 0) == -1) {
445 SU_DEBUG_1(("%s: cannot register\n", __func__));
446 goto error;
447 }
448
449 f->f_peer = f_peer;
450 f_peer->f_peer = f;
451 return 0;
452
453 error:
454 forwarder_destroy(f);
455 return SOCKET_ERROR;
456 }
457
458 /** Connection is complete. */
forwarder_connected(proxy_t * pr,su_wait_t * w,forwarder_t * f)459 int forwarder_connected(proxy_t *pr, su_wait_t *w, forwarder_t *f)
460 {
461 int events, error;
462 forwarder_t *f_peer;
463
464 events = su_wait_events(w, f->f_socket);
465
466 error = su_soerror(f->f_socket);
467
468 if (error) {
469 SU_DEBUG_1(("connect: %s\n", su_strerror(error)));
470 forwarder_destroy(f);
471 return 0;
472 }
473
474 su_root_unregister(pr->pr_root, f->f_wait + 1, forwarder_connected, f);
475
476 /* Wait for data, forward it to peer */
477 assert(f->f_peer);
478 f_peer = f->f_peer;
479 su_root_register(pr->pr_root, f->f_wait, forwarder_recv, f, 0);
480 su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0);
481
482 return 0;
483 }
484
485 /** Receive data, forward it to peer */
forwarder_recv(proxy_t * pr,su_wait_t * w,forwarder_t * f)486 int forwarder_recv(proxy_t *pr, su_wait_t *w, forwarder_t *f)
487 {
488 buffer_t b[1];
489 int n, events;
490
491 events = su_wait_events(w, f->f_socket);
492
493 n = recv(f->f_socket, b->b_data, sizeof(b->b_data), 0);
494
495 if (n > 0) {
496 b->b_sent = 0; b->b_used = n;
497 if (f->f_peer->f_buf) {
498 forwarder_append(f, b);
499 return 0;
500 }
501 if (forwarder_send(pr, f->f_peer, b) >= 0) {
502 if (b->b_sent < b->b_used) {
503 su_root_unregister(pr->pr_root, w, forwarder_recv, f);
504 su_root_register(pr->pr_root, f->f_peer->f_wait + 1,
505 forwarder_empty, f->f_peer, 0);
506 forwarder_append(f, b);
507 }
508 return 0;
509 }
510 else {
511 /* Error when sending */
512 }
513 }
514 if (n < 0) {
515 int error = su_errno();
516 SU_DEBUG_1(("recv: %s\n", su_strerror(error)));
517
518 if (error == EINTR || error == EAGAIN || error == EWOULDBLOCK) {
519 return 0;
520 }
521 /* XXX */
522 forwarder_destroy(f);
523 }
524
525 /* shutdown */
526 forwarder_shutdown(f);
527
528 return 0;
529 }
530
forwarder_send(proxy_t * pr,forwarder_t * f,buffer_t * b)531 int forwarder_send(proxy_t *pr, forwarder_t *f, buffer_t *b)
532 {
533 int n, error;
534
535 do {
536 n = send(f->f_socket, b->b_data + b->b_sent, b->b_used - b->b_sent, 0);
537
538 if (n < 0) {
539 error = su_errno();
540 if (error == EINTR)
541 continue;
542 SU_DEBUG_1(("send: %s\n", su_strerror(error)));
543 if (error != EAGAIN && error != EWOULDBLOCK)
544 return -error;
545 }
546 else {
547 f->f_sent += n;
548 }
549 }
550 while (n > 0 && (b->b_sent += n) < b->b_used);
551
552 return b->b_used - b->b_sent;
553 }
554
forwarder_append(forwarder_t * f,buffer_t * b0)555 int forwarder_append(forwarder_t *f, buffer_t *b0)
556 {
557 buffer_t *b, **bb;
558 int unsent;
559
560 /* Find last buffer */
561 for (bb = &f->f_buf; *bb; bb = &(*bb)->b_next)
562 ;
563
564 unsent = b0->b_used - b0->b_sent;
565 assert(unsent > 0);
566
567 b = su_alloc(f->f_pr->pr_home, offsetof(buffer_t, b_data[unsent]));
568 if (b) {
569 *bb = b;
570 b->b_next = NULL;
571 b->b_prev = bb;
572 b->b_used = unsent;
573 b->b_sent = 0;
574 memcpy(b->b_data, b0->b_data + b->b_sent, unsent);
575 }
576
577 return b ? 0 : -1;
578 }
579
580 /** Empty forwarder buffers */
forwarder_empty(proxy_t * pr,su_wait_t * w,forwarder_t * f)581 int forwarder_empty(proxy_t *pr, su_wait_t *w, forwarder_t *f)
582 {
583 buffer_t *b;
584 int n, events;
585
586 events = su_wait_events(w, f->f_socket);
587
588 while ((b = f->f_buf)) {
589 n = forwarder_send(f->f_pr, f, b);
590 if (n == 0) {
591 if ((f->f_buf = b->b_next))
592 b->b_next->b_prev = &f->f_buf;
593 su_free(f->f_pr->pr_home, b);
594 continue;
595 }
596 else if (n < 0) {
597 /* XXX */
598 }
599 break;
600 }
601
602 if (!f->f_buf) {
603 forwarder_t *f_peer = f->f_peer;
604
605 su_root_unregister(pr->pr_root, w, forwarder_empty, f);
606
607 if (!f->f_shutdown) {
608 /* Buffer is empty - start receiving */
609 su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0);
610 }
611 else {
612 if (shutdown(f->f_socket, 1) < 0) {
613 SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno())));
614 }
615 if (f_peer->f_shutdown) {
616 forwarder_close(f);
617 }
618 }
619 }
620
621 return 0;
622 }
623
forwarder_shutdown(forwarder_t * f)624 int forwarder_shutdown(forwarder_t *f)
625 {
626 forwarder_t *f_peer = f->f_peer;
627 su_sockaddr_t *su = f->f_dest;
628 char buf[SU_ADDRSIZE];
629
630 SU_DEBUG_3(("forwarder_shutdown: shutdown from %s:%u\n",
631 su_inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
632 ntohs(su->su_port)));
633
634 if (su_root_unregister(f->f_pr->pr_root, f->f_wait, forwarder_recv, f) < 0) {
635 SU_DEBUG_1(("%s: su_root_unregister failed\n", __func__));
636 }
637
638 if (shutdown(f->f_socket, 0) < 0) {
639 SU_DEBUG_1(("shutdown(0): %s\n", su_strerror(su_errno())));
640 }
641 f_peer->f_shutdown = 1;
642 if (!f_peer->f_buf) {
643 if (shutdown(f_peer->f_socket, 1) < 0) {
644 SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno())));
645 }
646 if (f->f_shutdown) {
647 forwarder_close(f);
648 }
649 }
650 return 0;
651 }
652
653 /** Close a peer pair */
forwarder_close(forwarder_t * f)654 void forwarder_close(forwarder_t *f)
655 {
656 su_sockaddr_t *su1, *su2;
657 char const *d1, *d2;
658 char buf1[SU_ADDRSIZE], buf2[SU_ADDRSIZE];
659
660 if (f->f_upstream)
661 su1 = f->f_dest, su2 = f->f_peer->f_dest, d1 = "up", d2 = "down";
662 else
663 su2 = f->f_dest, su1 = f->f_peer->f_dest, d2 = "up", d1 = "down";
664
665 SU_DEBUG_3(("forwarder_close: connection from %s:%u to %s:%d\n",
666 su_inet_ntop(su1->su_family, SU_ADDR(su1), buf1, sizeof(buf1)),
667 ntohs(su1->su_port),
668 su_inet_ntop(su2->su_family, SU_ADDR(su2), buf2, sizeof(buf2)),
669 ntohs(su2->su_port)));
670
671 forwarder_destroy(f);
672 }
673