1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 Copyright (c) 2013, Mozilla
4 
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are
9 met:
10 
11 * Redistributions of source code must retain the above copyright
12   notice, this list of conditions and the following disclaimer.
13 
14 * Redistributions in binary form must reproduce the above copyright
15   notice, this list of conditions and the following disclaimer in the
16   documentation and/or other materials provided with the distribution.
17 
18 * Neither the name of Adobe Systems, Network Resonance, Mozilla nor
19   the names of its contributors may be used to endorse or promote
20   products derived from this software without specific prior written
21   permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 
36 #include <nr_api.h>
37 
38 #include <assert.h>
39 
40 #include "nr_proxy_tunnel.h"
41 
42 #define MAX_HTTP_CONNECT_ADDR_SIZE 256
43 #define MAX_HTTP_CONNECT_BUFFER_SIZE 1024
44 #define MAX_ALPN_LENGTH 64
45 #ifndef CRLF
46 #define CRLF "\r\n"
47 #endif
48 #define END_HEADERS CRLF CRLF
49 
50 typedef enum {
51   PROXY_TUNNEL_NONE=0,
52   PROXY_TUNNEL_REQUESTED,
53   PROXY_TUNNEL_CONNECTED,
54   PROXY_TUNNEL_CLOSED,
55   PROXY_TUNNEL_FAILED
56 } nr_socket_proxy_tunnel_state;
57 
58 typedef struct nr_socket_proxy_tunnel_ {
59   nr_proxy_tunnel_config *config;
60   nr_socket *inner;
61   nr_transport_addr remote_addr;
62   nr_socket_proxy_tunnel_state state;
63   char buffer[MAX_HTTP_CONNECT_BUFFER_SIZE];
64   size_t buffered_bytes;
65   void *resolver_handle;
66 } nr_socket_proxy_tunnel;
67 
68 typedef struct nr_socket_wrapper_factory_proxy_tunnel_ {
69   nr_proxy_tunnel_config *config;
70 } nr_socket_wrapper_factory_proxy_tunnel;
71 
72 static int nr_socket_proxy_tunnel_destroy(void **objpp);
73 static int nr_socket_proxy_tunnel_getfd(void *obj, NR_SOCKET *fd);
74 static int nr_socket_proxy_tunnel_getaddr(void *obj, nr_transport_addr *addrp);
75 static int nr_socket_proxy_tunnel_connect(void *sock, nr_transport_addr *addr);
76 static int nr_socket_proxy_tunnel_write(void *obj, const void *msg, size_t len, size_t *written);
77 static int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen, size_t *len);
78 static int nr_socket_proxy_tunnel_close(void *obj);
79 
80 int nr_proxy_tunnel_config_copy(nr_proxy_tunnel_config *config, nr_proxy_tunnel_config **copypp);
81 
82 int nr_socket_wrapper_factory_proxy_tunnel_wrap(void *obj,
83                                                 nr_socket *inner,
84                                                 nr_socket **socketpp);
85 
86 int nr_socket_wrapper_factory_proxy_tunnel_destroy(void **objpp);
87 
88 static nr_socket_vtbl nr_socket_proxy_tunnel_vtbl={
89   1,
90   nr_socket_proxy_tunnel_destroy,
91   0,
92   0,
93   nr_socket_proxy_tunnel_getfd,
94   nr_socket_proxy_tunnel_getaddr,
95   nr_socket_proxy_tunnel_connect,
96   nr_socket_proxy_tunnel_write,
97   nr_socket_proxy_tunnel_read,
98   nr_socket_proxy_tunnel_close
99 };
100 
send_http_connect(nr_socket_proxy_tunnel * sock)101 static int send_http_connect(nr_socket_proxy_tunnel *sock)
102 {
103   int r, _status;
104   int port;
105   int printed;
106   char addr[MAX_HTTP_CONNECT_ADDR_SIZE];
107   char mesg[MAX_HTTP_CONNECT_ADDR_SIZE + MAX_ALPN_LENGTH + 128];
108   size_t offset = 0;
109   size_t bytes_sent;
110 
111   r_log(LOG_GENERIC,LOG_DEBUG,"send_http_connect");
112 
113   if ((r=nr_transport_addr_get_port(&sock->remote_addr, &port))) {
114     ABORT(r);
115   }
116 
117   if ((r=nr_transport_addr_get_addrstring(&sock->remote_addr, addr, sizeof(addr)))) {
118     ABORT(r);
119   }
120 
121   printed = snprintf(mesg + offset, sizeof(mesg) - offset,
122                      "CONNECT %s:%d HTTP/1.0", addr, port);
123   offset += printed;
124   if (printed < 0 || (offset >= sizeof(mesg))) {
125     ABORT(R_FAILED);
126   }
127 
128   if (sock->config->alpn) {
129     printed = snprintf(mesg + offset, sizeof(mesg) - offset,
130                        CRLF "ALPN: %s", sock->config->alpn);
131     offset += printed;
132     if (printed < 0 || (offset >= sizeof(mesg))) {
133       ABORT(R_FAILED);
134     }
135   }
136   if (offset + sizeof(END_HEADERS) >= sizeof(mesg)) {
137     ABORT(R_FAILED);
138   }
139   memcpy(mesg + offset, END_HEADERS, strlen(END_HEADERS));
140   offset += strlen(END_HEADERS);
141 
142   if ((r=nr_socket_write(sock->inner, mesg, offset, &bytes_sent, 0))) {
143     ABORT(r);
144   }
145 
146   if (bytes_sent < offset) {
147     /* TODO(bug 1116583): buffering and wait for */
148     r_log(LOG_GENERIC,LOG_DEBUG,"send_http_connect should be buffering %lu", (unsigned long)bytes_sent);
149     ABORT(R_IO_ERROR);
150   }
151 
152   sock->state = PROXY_TUNNEL_REQUESTED;
153 
154   _status = 0;
155 abort:
156   return(_status);
157 }
158 
find_http_terminator(char * response,size_t len)159 static char *find_http_terminator(char *response, size_t len)
160 {
161   char *term = response;
162   char *end = response + len;
163   int N = strlen(END_HEADERS);
164 
165   for (; term = memchr(term, '\r', end - term); ++term) {
166     if (end - term >= N && memcmp(term, END_HEADERS, N) == 0) {
167       return term;
168     }
169   }
170 
171   return NULL;
172 }
173 
parse_http_response(char * begin,char * end,unsigned int * status)174 static int parse_http_response(char *begin, char *end, unsigned int *status)
175 {
176   size_t len = end - begin;
177   char response[MAX_HTTP_CONNECT_BUFFER_SIZE + 1];
178 
179   // len should *never* be greater than nr_socket_proxy_tunnel::buffered_bytes.
180   // Which in turn should never be greater nr_socket_proxy_tunnel::buffer size.
181   assert(len <= MAX_HTTP_CONNECT_BUFFER_SIZE);
182   if (len > MAX_HTTP_CONNECT_BUFFER_SIZE) {
183     return R_BAD_DATA;
184   }
185 
186   memcpy(response, begin, len);
187   response[len] = '\0';
188 
189   // http://www.rfc-editor.org/rfc/rfc7230.txt
190   // status-line    = HTTP-version SP status-code SP reason-phrase CRLF
191   // HTTP-version   = HTTP-name "/" DIGIT "." DIGIT
192   // HTTP-name      = "HTTP" ; "HTTP", case-sensitive
193   // status-code    = 3DIGIT
194 
195   if (sscanf(response, "HTTP/%*u.%*u %u", status) != 1) {
196     r_log(LOG_GENERIC,LOG_WARNING,"parse_http_response failed to find status (%s)", response);
197     return R_BAD_DATA;
198   }
199 
200   return 0;
201 }
202 
nr_socket_proxy_tunnel_destroy(void ** objpp)203 static int nr_socket_proxy_tunnel_destroy(void **objpp)
204 {
205   nr_socket_proxy_tunnel *sock;
206 
207   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_destroy");
208 
209   if (!objpp || !*objpp)
210     return 0;
211 
212   sock = (nr_socket_proxy_tunnel *)*objpp;
213   *objpp = 0;
214 
215   if (sock->resolver_handle) {
216     nr_resolver_cancel(sock->config->resolver, sock->resolver_handle);
217   }
218 
219   nr_proxy_tunnel_config_destroy(&sock->config);
220   nr_socket_destroy(&sock->inner);
221   RFREE(sock);
222 
223   return 0;
224 }
225 
nr_socket_proxy_tunnel_getfd(void * obj,NR_SOCKET * fd)226 static int nr_socket_proxy_tunnel_getfd(void *obj, NR_SOCKET *fd)
227 {
228   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel *)obj;
229 
230   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_getfd");
231 
232   return nr_socket_getfd(sock->inner, fd);
233 }
234 
nr_socket_proxy_tunnel_getaddr(void * obj,nr_transport_addr * addrp)235 static int nr_socket_proxy_tunnel_getaddr(void *obj, nr_transport_addr *addrp)
236 {
237   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel *)obj;
238 
239   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_getaddr");
240 
241   return nr_socket_getaddr(sock->inner, addrp);
242 }
243 
nr_socket_proxy_tunnel_resolved_cb(void * obj,nr_transport_addr * proxy_addr)244 static int nr_socket_proxy_tunnel_resolved_cb(void *obj, nr_transport_addr *proxy_addr)
245 {
246   int r, _status;
247   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
248 
249   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_resolved_cb");
250 
251   /* Mark the socket resolver as completed */
252   sock->resolver_handle = 0;
253 
254   if (proxy_addr) {
255     r_log(LOG_GENERIC,LOG_DEBUG,"Resolved proxy address %s -> %s",
256         sock->config->proxy_host, proxy_addr->as_string);
257   }
258   else {
259     r_log(LOG_GENERIC,LOG_WARNING,"Failed to resolve proxy %s",
260         sock->config->proxy_host);
261     /* TODO: Mozilla bug 1241758: because of the callback the return value goes
262      * nowhere, so we can't mark the candidate as failed, so everything depends
263      * on the overall timeouts in this case. */
264     sock->state = PROXY_TUNNEL_FAILED;
265     ABORT(R_NOT_FOUND);
266   }
267 
268   if ((r=nr_socket_connect(sock->inner, proxy_addr))) {
269     ABORT(r);
270   }
271 
272   _status = 0;
273 abort:
274   return(_status);
275 }
276 
nr_socket_proxy_tunnel_connect(void * obj,nr_transport_addr * addr)277 int nr_socket_proxy_tunnel_connect(void *obj, nr_transport_addr *addr)
278 {
279   int r, _status;
280   int has_addr;
281   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
282   nr_proxy_tunnel_config *config = sock->config;
283   nr_transport_addr proxy_addr, local_addr;
284   nr_resolver_resource resource;
285 
286   if ((r=nr_transport_addr_copy(&sock->remote_addr, addr))) {
287     ABORT(r);
288   }
289 
290   assert(config->proxy_host);
291 
292   /* Check if the proxy_host is already an IP address */
293   has_addr = !nr_str_port_to_transport_addr(config->proxy_host,
294       config->proxy_port, IPPROTO_TCP, &proxy_addr);
295 
296   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_connect: %s", config->proxy_host);
297 
298   if (!has_addr && !config->resolver) {
299     r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_connect name resolver not configured");
300     ABORT(R_NOT_FOUND);
301   }
302 
303   if (!has_addr) {
304     resource.domain_name=config->proxy_host;
305     resource.port=config->proxy_port;
306     resource.stun_turn=NR_RESOLVE_PROTOCOL_TURN;
307     resource.transport_protocol=IPPROTO_TCP;
308 
309     if ((r=nr_socket_getaddr(sock->inner, &local_addr))) {
310       r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_connect failed to get local address");
311       ABORT(r);
312     }
313 
314     switch(local_addr.ip_version) {
315       case NR_IPV4:
316         resource.address_family=AF_INET;
317         break;
318       case NR_IPV6:
319         resource.address_family=AF_INET6;
320         break;
321       default:
322         ABORT(R_BAD_ARGS);
323     }
324 
325     r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_connect: nr_resolver_resolve");
326     if ((r=nr_resolver_resolve(config->resolver, &resource,
327             nr_socket_proxy_tunnel_resolved_cb, (void *)sock, &sock->resolver_handle))) {
328       r_log(LOG_GENERIC,LOG_ERR,"Could not invoke DNS resolver");
329       ABORT(r);
330     }
331 
332     ABORT(R_WOULDBLOCK);
333   }
334 
335   if ((r=nr_socket_connect(sock->inner, &proxy_addr))) {
336     ABORT(r);
337   }
338 
339   _status=0;
340 abort:
341   return(_status);
342 }
343 
nr_socket_proxy_tunnel_write(void * obj,const void * msg,size_t len,size_t * written)344 int nr_socket_proxy_tunnel_write(void *obj, const void *msg, size_t len,
345                                  size_t *written)
346 {
347   int r, _status;
348   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
349 
350   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_write");
351 
352   if (sock->state >= PROXY_TUNNEL_CLOSED) {
353     return R_FAILED;
354   }
355 
356   if (sock->state == PROXY_TUNNEL_NONE) {
357     if ((r=send_http_connect(sock))) {
358       ABORT(r);
359     }
360   }
361 
362   if (sock->state != PROXY_TUNNEL_CONNECTED) {
363     return R_WOULDBLOCK;
364   }
365 
366   if ((r=nr_socket_write(sock->inner, msg, len, written, 0))) {
367     ABORT(r);
368   }
369 
370   _status=0;
371 abort:
372   return(_status);
373 }
374 
nr_socket_proxy_tunnel_read(void * obj,void * restrict buf,size_t maxlen,size_t * len)375 int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen,
376                                 size_t *len)
377 {
378   int r, _status;
379   char *ptr, *http_term;
380   size_t bytes_read, available_buffer_len, maxlen_int;
381   size_t pending;
382   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
383   unsigned int http_status;
384 
385   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_read");
386 
387   *len = 0;
388 
389   if (sock->state >= PROXY_TUNNEL_CLOSED) {
390     return R_FAILED;
391   }
392 
393   if (sock->state == PROXY_TUNNEL_CONNECTED) {
394     return nr_socket_read(sock->inner, buf, maxlen, len, 0);
395   }
396 
397   if (sock->buffered_bytes >= sizeof(sock->buffer)) {
398     r_log(LOG_GENERIC,LOG_ERR,"buffer filled waiting for CONNECT response");
399     assert(sock->buffered_bytes == sizeof(sock->buffer));
400     ABORT(R_INTERNAL);
401   }
402 
403   /* Do not read more than maxlen bytes */
404   available_buffer_len = sizeof(sock->buffer) - sock->buffered_bytes;
405   maxlen_int = maxlen < available_buffer_len ? maxlen : available_buffer_len;
406   if ((r=nr_socket_read(sock->inner, sock->buffer + sock->buffered_bytes,
407           maxlen_int, &bytes_read, 0))) {
408     ABORT(r);
409   }
410 
411   sock->buffered_bytes += bytes_read;
412 
413   if (http_term = find_http_terminator(sock->buffer, sock->buffered_bytes)) {
414     if ((r = parse_http_response(sock->buffer, http_term, &http_status))) {
415       ABORT(r);
416     }
417 
418     /* TODO (bug 1115934): Handle authentication challenges. */
419     if (http_status < 200 || http_status >= 300) {
420       r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_read unable to connect %u",
421             http_status);
422       ABORT(R_FAILED);
423     }
424 
425     sock->state = PROXY_TUNNEL_CONNECTED;
426 
427     ptr = http_term + strlen(END_HEADERS);
428     pending = sock->buffered_bytes - (ptr - sock->buffer);
429 
430     if (pending == 0) {
431       ABORT(R_WOULDBLOCK);
432     }
433 
434     assert(pending <= maxlen);
435     *len = pending;
436 
437     memcpy(buf, ptr, *len);
438   }
439 
440   _status=0;
441 abort:
442   if (_status && _status != R_WOULDBLOCK) {
443       sock->state = PROXY_TUNNEL_FAILED;
444   }
445   return(_status);
446 }
447 
nr_socket_proxy_tunnel_close(void * obj)448 int nr_socket_proxy_tunnel_close(void *obj)
449 {
450   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
451 
452   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_close");
453 
454   if (sock->resolver_handle) {
455     nr_resolver_cancel(sock->config->resolver, sock->resolver_handle);
456     sock->resolver_handle = 0;
457   }
458 
459   sock->state = PROXY_TUNNEL_CLOSED;
460 
461   return nr_socket_close(sock->inner);
462 }
463 
nr_proxy_tunnel_config_create(nr_proxy_tunnel_config ** configpp)464 int nr_proxy_tunnel_config_create(nr_proxy_tunnel_config **configpp)
465 {
466   int _status;
467   nr_proxy_tunnel_config *configp=0;
468 
469   r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_create");
470 
471   if (!(configp=RCALLOC(sizeof(nr_proxy_tunnel_config))))
472     ABORT(R_NO_MEMORY);
473 
474   *configpp=configp;
475   _status=0;
476 abort:
477   return(_status);
478 }
479 
nr_proxy_tunnel_config_destroy(nr_proxy_tunnel_config ** configpp)480 int nr_proxy_tunnel_config_destroy(nr_proxy_tunnel_config **configpp)
481 {
482   nr_proxy_tunnel_config *configp;
483 
484   r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_destroy");
485 
486   if (!configpp || !*configpp)
487     return 0;
488 
489   configp = *configpp;
490   *configpp = 0;
491 
492   RFREE(configp->proxy_host);
493   RFREE(configp->alpn);
494   RFREE(configp);
495 
496   return 0;
497 }
498 
nr_proxy_tunnel_config_set_proxy(nr_proxy_tunnel_config * config,const char * host,UINT2 port)499 int nr_proxy_tunnel_config_set_proxy(nr_proxy_tunnel_config *config,
500                                      const char *host, UINT2 port)
501 {
502   char *hostdup;
503 
504   r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_set_proxy %s %d", host, port);
505 
506   if (!host) {
507     return R_BAD_ARGS;
508   }
509 
510   if (!(hostdup = r_strdup(host))) {
511     return R_NO_MEMORY;
512   }
513 
514   if (config->proxy_host) {
515     RFREE(config->proxy_host);
516   }
517 
518   config->proxy_host = hostdup;
519   config->proxy_port = port;
520 
521   return 0;
522 }
523 
nr_proxy_tunnel_config_set_resolver(nr_proxy_tunnel_config * config,nr_resolver * resolver)524 int nr_proxy_tunnel_config_set_resolver(nr_proxy_tunnel_config *config,
525                                         nr_resolver *resolver)
526 {
527   r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_set_resolver");
528 
529   config->resolver = resolver;
530 
531   return 0;
532 }
533 
nr_proxy_tunnel_config_set_alpn(nr_proxy_tunnel_config * config,const char * alpn)534 int nr_proxy_tunnel_config_set_alpn(nr_proxy_tunnel_config *config,
535                                     const char *alpn)
536 {
537   r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_set_alpn");
538 
539   if (alpn && (strlen(alpn) > MAX_ALPN_LENGTH)) {
540     return R_BAD_ARGS;
541   }
542 
543   if (config->alpn) {
544     RFREE(config->alpn);
545   }
546 
547   config->alpn = NULL;
548 
549   if (alpn) {
550     char *alpndup = r_strdup(alpn);
551 
552     if (!alpndup) {
553       return R_NO_MEMORY;
554     }
555 
556     config->alpn = alpndup;
557   }
558 
559   return 0;
560 }
561 
nr_proxy_tunnel_config_copy(nr_proxy_tunnel_config * config,nr_proxy_tunnel_config ** copypp)562 int nr_proxy_tunnel_config_copy(nr_proxy_tunnel_config *config, nr_proxy_tunnel_config **copypp)
563 {
564   int r,_status;
565   nr_proxy_tunnel_config *copy = 0;
566 
567   if ((r=nr_proxy_tunnel_config_create(&copy)))
568     ABORT(r);
569 
570   if ((r=nr_proxy_tunnel_config_set_proxy(copy, config->proxy_host, config->proxy_port)))
571     ABORT(r);
572 
573   if ((r=nr_proxy_tunnel_config_set_resolver(copy, config->resolver)))
574     ABORT(r);
575 
576   if ((r=nr_proxy_tunnel_config_set_alpn(copy, config->alpn)))
577     ABORT(r);
578 
579   *copypp = copy;
580 
581   _status=0;
582 abort:
583   if (_status) {
584     nr_proxy_tunnel_config_destroy(&copy);
585   }
586   return(_status);
587 }
588 
589 
nr_socket_proxy_tunnel_create(nr_proxy_tunnel_config * config,nr_socket * inner,nr_socket ** socketpp)590 int nr_socket_proxy_tunnel_create(nr_proxy_tunnel_config *config,
591                                   nr_socket *inner,
592                                   nr_socket **socketpp)
593 {
594   int r, _status;
595   nr_socket_proxy_tunnel *sock=0;
596   void *sockv;
597 
598   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_create");
599 
600   if (!config) {
601     ABORT(R_BAD_ARGS);
602   }
603 
604   if (!(sock=RCALLOC(sizeof(nr_socket_proxy_tunnel)))) {
605     ABORT(R_NO_MEMORY);
606   }
607 
608   sock->inner = inner;
609 
610   if ((r=nr_proxy_tunnel_config_copy(config, &sock->config)))
611     ABORT(r);
612 
613   if ((r=nr_socket_create_int(sock, &nr_socket_proxy_tunnel_vtbl, socketpp))) {
614     ABORT(r);
615   }
616 
617   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_created");
618 
619   _status=0;
620 abort:
621   if (_status) {
622     sockv = sock;
623     nr_socket_proxy_tunnel_destroy(&sockv);
624   }
625   return(_status);
626 }
627 
nr_socket_wrapper_factory_proxy_tunnel_wrap(void * obj,nr_socket * inner,nr_socket ** socketpp)628 int nr_socket_wrapper_factory_proxy_tunnel_wrap(void *obj,
629                                                 nr_socket *inner,
630                                                 nr_socket **socketpp)
631 {
632   nr_socket_wrapper_factory_proxy_tunnel *wrapper = (nr_socket_wrapper_factory_proxy_tunnel *)obj;
633 
634   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_wrapper_factory_proxy_tunnel_wrap");
635 
636   return nr_socket_proxy_tunnel_create(wrapper->config, inner, socketpp);
637 }
638 
639 
nr_socket_wrapper_factory_proxy_tunnel_destroy(void ** objpp)640 int nr_socket_wrapper_factory_proxy_tunnel_destroy(void **objpp) {
641   nr_socket_wrapper_factory_proxy_tunnel *wrapper;
642 
643   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_wrapper_factory_proxy_tunnel_destroy");
644 
645   if (!objpp || !*objpp)
646     return 0;
647 
648   wrapper = (nr_socket_wrapper_factory_proxy_tunnel *)*objpp;
649   *objpp = 0;
650 
651   nr_proxy_tunnel_config_destroy(&wrapper->config);
652   RFREE(wrapper);
653 
654   return 0;
655 }
656 
657 static nr_socket_wrapper_factory_vtbl proxy_tunnel_wrapper_vtbl = {
658   nr_socket_wrapper_factory_proxy_tunnel_wrap,
659   nr_socket_wrapper_factory_proxy_tunnel_destroy
660 };
661 
nr_socket_wrapper_factory_proxy_tunnel_create(nr_proxy_tunnel_config * config,nr_socket_wrapper_factory ** factory)662 int nr_socket_wrapper_factory_proxy_tunnel_create(nr_proxy_tunnel_config *config,
663                                                   nr_socket_wrapper_factory **factory) {
664   int r,_status;
665   nr_socket_wrapper_factory_proxy_tunnel *wrapper=0;
666   void *wrapperv;
667 
668   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_wrapper_factory_proxy_tunnel_create");
669 
670   if (!(wrapper=RCALLOC(sizeof(nr_socket_wrapper_factory_proxy_tunnel))))
671     ABORT(R_NO_MEMORY);
672 
673   if ((r=nr_proxy_tunnel_config_copy(config, &wrapper->config)))
674     ABORT(r);
675 
676   if ((r=nr_socket_wrapper_factory_create_int(wrapper, &proxy_tunnel_wrapper_vtbl, factory)))
677     ABORT(r);
678 
679   _status=0;
680 abort:
681   if (_status) {
682     wrapperv = wrapper;
683     nr_socket_wrapper_factory_proxy_tunnel_destroy(&wrapperv);
684   }
685   return(_status);
686 }
687