source: verona/phapi/ph_socks_rtp.c @ 484:c2bacb67c8f0

Last change on this file since 484:c2bacb67c8f0 was 484:c2bacb67c8f0, checked in by laurent@…, 12 months ago

WIN32 : alloca is missing

File size: 9.6 KB
Line 
1/*
2Copyright (c) 2011, MBDSYS
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without modification, are permitted provided that
6the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice, this list of conditions
9      and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
11      following disclaimer in the documentation and/or other materials provided with the distribution.
12 * Neither the name of the MBDSYS nor the names of its contributors may be used to endorse or promote products
13      derived from this software without specific prior written permission.
14
15THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
16BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
21EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 */
23
24#include <ortp/ortp.h>
25
26#ifdef _MSC_VER
27#include <Mstcpip.h>
28#include <stdint.h>
29#include <malloc.h>
30typedef uint32_t in_addr_t;
31#define sockioctl ioctlsocket
32#define MSG_DONTWAIT 0
33#else
34#include <netdb.h>
35#define closesocket close
36#endif
37
38#ifndef WIN32
39#define closesocket close
40#else
41static int
42socknonblocking(SOCKET sock, int yes)
43{
44   return  sockioctl(sock, FIONBIO, (char *)&yes);
45}
46
47static int
48recvAll(SOCKET sock, char* buf, size_t s)
49{
50        // the socket is in non blocking mode in WIN32
51        int count = 100;
52        int total = 0;
53
54        while(total < (int) s && count--) {
55                int res = recv(sock, buf, s, 0);
56
57                if (res == SOCKET_ERROR) {
58                        int err = WSAGetLastError();
59
60                        if (err == WSAEWOULDBLOCK) {
61                                continue;
62                        }
63                        return -1;
64                }
65                total += res;
66                buf += res;
67                s -= res;
68
69        }
70
71        return total;
72}
73#endif
74
75#ifndef MSG_NOSIGNAL
76#define MSG_NOSIGNAL 0
77#endif
78
79#ifdef ENABLE_SOCKS
80
81
82#define as_sin(x) (*(struct sockaddr_in*)(x))
83static char rtp_socks_proxy[64];
84static int rtp_socks_port = 8080;
85
86
87struct rtp_socks_data {
88        ortp_socket_t    socket;
89
90        struct sockaddr  addr;
91        in_addr_t      publicip;
92        int16_t              publicport;
93        int    pfxlen;
94        union {
95                uint32_t plen;
96                char buf[4];
97        };
98};
99
100typedef struct rtp_socks_data RtpSocksData;
101
102static int
103rtp_socks_sendto(RtpTransport *t, mblk_t *m, int flags, const struct sockaddr *to, socklen_t tolen){
104        size_t slen;
105        size_t hlen;
106        int res;
107        uint32_t plen;
108        RtpSocksData *sk = (RtpSocksData*) t->data;
109        char*  tmpbuf;
110
111#ifdef _MSC_VER
112#pragma pack(push, r1, 1)
113                __declspec(align(1)) struct {
114                        uint32_t len;
115                        in_addr_t addr;
116                        uint16_t port;
117                } connreq;
118#pragma pack(pop, r1)
119#else
120                struct {
121                        uint32_t len;
122                        in_addr_t addr;
123                        uint16_t port;
124                } connreq __attribute__((aligned (1) , packed));
125#endif
126
127        if (as_sin(&sk->addr).sin_addr.s_addr == 0) {
128                /*
129                 *  this is first time we send data over this tunnel and the tunnel server still does
130                 *  not now the tunnel destination address.
131                 *  So we're sending specially formatted packet (length prefix == 0) followed by the tunnel
132                 *  destination address
133                 */
134                sk->addr = *to;
135                connreq.len = 0;
136                connreq.addr = as_sin(&sk->addr).sin_addr.s_addr;
137                connreq.port =  as_sin(&sk->addr).sin_port;
138
139                res = send(sk->socket, &connreq, 10, MSG_DONTWAIT|MSG_NOSIGNAL);
140                if (res != 10)
141                        return -1;
142        }
143
144        msgpullup(m,msgdsize(m));
145
146        slen=m->b_wptr-m->b_rptr;
147        plen = htonl(slen);
148        tmpbuf = (char* )alloca(slen+4);
149        *(uint32_t*)tmpbuf = plen;
150        memcpy(tmpbuf+4, m->b_rptr, slen);
151
152        res = send(sk->socket, tmpbuf, slen+4, MSG_DONTWAIT|MSG_NOSIGNAL);
153        if (res != slen+4)
154                return -1;
155        return res;
156}
157
158static int
159rtp_socks_recvfrom(RtpTransport *t, mblk_t *m, int flags, struct sockaddr *from, socklen_t *fromlen){
160
161        int res;
162        int expectlen = 0;
163        size_t bufsize = m->b_datap->db_lim - m->b_datap->db_base;
164        RtpSocksData *sk = (RtpSocksData*) t->data;
165
166        if (sk->pfxlen < 4) {
167                res = recv(sk->socket, sk->buf+sk->pfxlen, 4 - sk->pfxlen, MSG_DONTWAIT);
168                if (res > 0)
169                        sk->pfxlen += res;
170                else
171                        return res;
172
173                if (sk->pfxlen == 4)
174                        expectlen = ntohl(sk->plen);
175        }
176
177
178        if (expectlen > bufsize) {
179                return -1;
180        }
181
182        sk->pfxlen = 0;
183        if (!expectlen)
184                return 0;
185
186#ifdef WIN32
187        res = recvAll(sk->socket, m->b_wptr, expectlen);
188#else
189        res = recv(sk->socket, m->b_wptr, expectlen, 0);
190#endif
191        if (res <= 0)
192                return res;
193
194        *(struct sockaddr_in*) from = *(struct sockaddr_in*) &(sk->addr);
195        *fromlen = sizeof(struct sockaddr_in);
196        return res;
197}
198
199
200static ortp_socket_t
201rtp_socks_getsocket(RtpTransport *t)
202{
203        return ((RtpSocksData*)(t->data))->socket;
204}
205
206void rtp_socks_close(RtpTransport* t)
207{
208        RtpSocksData *sk = (RtpSocksData *) t->data;
209
210        if (sk->socket)
211                closesocket(sk->socket);
212
213        ortp_free(sk);
214        ortp_free(t);
215}
216
217
218#define as_sin(x) (*(struct sockaddr_in*)x)
219
220#ifdef _MSC_VER
221#pragma pack(push, r1, 1)
222__declspec(align(1)) struct socks5_req {
223        char    ver;          /* Version number */
224        char    cmd;          /* Command */
225        char    _nop;         /* Reserved */
226        char    atp ;        /* Address type */
227        uint32_t destip;    /* Dest address */
228        uint16_t dport;    /* Dest port */
229};
230#pragma pack(pop, r1)
231#else
232struct socks5_req {
233        char    ver;          /* Version number */
234        char    cmd;          /* Command */
235        char    _nop;         /* Reserved */
236        char    atp ;        /* Address type */
237        uint32_t destip;    /* Dest address */
238        uint16_t dport;    /* Dest port */
239} __attribute__((aligned (1) , packed));
240#endif
241
242static int
243rtp_socks_negotiate(RtpSocksData *sk)
244{
245        int ret;
246        char msg1[] = { 0x05, 0x01, 0x00 };
247        char auth[2];
248        struct socks5_req req, resp;
249        struct in_addr ina;
250
251        ret = send(sk->socket, msg1, 3, MSG_NOSIGNAL);
252        if (ret != 3)
253                return -1;
254
255        ret = recv(sk->socket, auth, 2, 0);
256        if (ret != 2)
257                return -1;
258
259        if (auth[0] != 5) /* check protocol version */
260                return -1;
261        if (auth[1] != 0) /* check auth type */
262                return -1;
263
264        req.ver = 5;
265        req.cmd = 4;    /* (sk->socktype & SOCKST_UDPMASK) ? 4 : 1; */
266        req._nop = 0;
267        req.atp = 1;
268        req.destip = as_sin(&sk->addr).sin_addr.s_addr;
269        req.dport  = as_sin(&sk->addr).sin_port;
270
271        ret = send(sk->socket, &req, sizeof(req), MSG_NOSIGNAL);
272        if (ret != sizeof(req))
273                return -1;
274
275        ret = recv(sk->socket, &resp, 4, 0);
276        if (ret != 4)
277                return -1;
278
279        if (resp.ver != 5)
280                return -1;
281
282        if (resp.cmd != 0)
283                return -1;
284
285        if (resp.atp != 1)
286                return -1;
287
288        ret = recv(sk->socket, &resp.destip, 6, MSG_NOSIGNAL);
289        if (ret != 6)
290                return 0;
291
292        sk->publicip = resp.destip;
293        sk->publicport = resp.dport;
294
295#ifdef WIN32
296        /* make socket non-blocking */
297        {
298                char yes = 1;
299
300                 sockioctl(sk->socket, FIONBIO, (char *)&yes);
301        }
302#endif
303#ifdef __APPLE__
304        {
305                int set = 1;
306                setsockopt(sk->socket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
307        }
308#endif
309
310
311        return 0;
312}
313
314int rtp_socks_transport_address(RtpTransport *t, in_addr_t *pubip,  int* pubport)
315{
316        if (t) {
317                RtpSocksData *sk = (RtpSocksData*) t->data;
318                if (!sk)
319                        return -1;
320                if (!pubip || !pubport)
321                        return -1;
322
323                *pubip = sk->publicip;
324                *pubport = ntohs(sk->publicport);
325                return 0;
326        }
327        return -1;
328
329}
330
331RtpTransport *
332rtp_socks_transport_new(const char *peer, int pport)
333{
334        RtpTransport *t;
335        RtpSocksData *sk = ortp_new0(RtpSocksData, 1);
336        ortp_socket_t sock;
337    struct addrinfo hints;
338    struct addrinfo *result, *rp;
339        int err;
340
341
342
343        if (!sk)
344                return 0;
345
346    memset(&hints, 0, sizeof(hints));
347    hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
348    hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
349    hints.ai_flags = 0;    /* For wildcard IP address */
350    hints.ai_protocol = 0;          /* Any protocol */
351    hints.ai_canonname = NULL;
352    hints.ai_addr = NULL;
353    hints.ai_next = NULL;
354
355
356        err = getaddrinfo(rtp_socks_proxy, 0, &hints, &result);
357        if (err)
358                return 0;
359
360        for (rp = result; rp; rp = rp->ai_next) {
361                if (rp->ai_protocol && rp->ai_protocol != IPPROTO_TCP) {
362                        continue;
363                }
364
365                sock = (int) socket(rp->ai_family, rp->ai_socktype,
366                                rp->ai_protocol);
367
368                if (sock)
369                        break;
370
371
372        }
373
374
375        t =  ortp_new0(RtpTransport,1);
376        if (!t) {
377                ortp_free(sk);
378                freeaddrinfo(result);
379                return 0;
380        }
381
382        t->data = sk;
383        t->t_getsocket = rtp_socks_getsocket;
384        t->t_recvfrom = rtp_socks_recvfrom;
385        t->t_sendto = rtp_socks_sendto;
386
387
388        if (sock < 0) {
389                rtp_socks_close(t);
390                freeaddrinfo(result);
391                return 0;
392        }
393
394        sk->socket = sock;
395        as_sin(rp->ai_addr).sin_port = htons(rtp_socks_port);
396
397    if (!connect(sock, rp->ai_addr, rp->ai_addrlen)) {
398        freeaddrinfo(result);
399        result = 0;
400        if (peer && *peer) {
401
402                memset(&hints, 0, sizeof(hints));
403                hints.ai_family = AF_INET;    /* Allow IPv4 or IPv6 */
404                hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
405                hints.ai_flags = AI_PASSIVE;    /* For wildcard IP address */
406                hints.ai_protocol = 0;          /* Any protocol */
407                hints.ai_canonname = NULL;
408                hints.ai_addr = NULL;
409                hints.ai_next = NULL;
410
411                err = getaddrinfo(peer, 0, &hints, &result);
412                sk->addr = *result->ai_addr;
413        }
414
415        as_sin(&sk->addr).sin_port = htons(pport);
416        if (!rtp_socks_negotiate(sk)) {
417                if (result)
418                        freeaddrinfo(result);
419                return t;
420        }
421    }
422
423    rtp_socks_close(t);
424        if (result)
425                freeaddrinfo(result);
426    return 0;
427}
428
429void rtp_set_tunnel_server(const char* server, const char* port)
430{
431        osip_strncpy(rtp_socks_proxy, server, sizeof(rtp_socks_proxy) - 1);
432        rtp_socks_port = atoi(port);
433}
434
435int ortp_socks_init(void)
436{
437        return 0;
438}
439
440#endif
Note: See TracBrowser for help on using the repository browser.