source: verona/phapi/ph_socks_rtp.c @ 479:e40d35c7c619

Last change on this file since 479:e40d35c7c619 was 479:e40d35c7c619, checked in by Vadim Lebedev <vadim@…>, 12 months ago

Change rtp_sock_sendto to write all data using ONE syscall

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