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