source: trunk/libtransmission/natpmp.c @ 1463

Last change on this file since 1463 was 1463, checked in by joshe, 15 years ago

Remove natpmp and upnp locks and rely on the shared lock.

  • Property svn:keywords set to Date Rev Author Id
File size: 22.2 KB
Line 
1/******************************************************************************
2 * $Id: natpmp.c 1463 2007-02-06 05:37:48Z joshe $
3 *
4 * Copyright (c) 2006 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include "transmission.h"
26
27#define PMP_PORT                5351
28#define PMP_MCAST_ADDR          "224.0.0.1"
29#define PMP_INITIAL_DELAY       250     /* ms, 1/4 second */
30#define PMP_TOTAL_DELAY         120000  /* ms, 2 minutes */
31#define PMP_VERSION             0
32#define PMP_OPCODE_GETIP        0
33#define PMP_OPCODE_ADDUDP       1
34#define PMP_OPCODE_ADDTCP       2
35#define PMP_LIFETIME            3600    /* secs, one hour */
36#define PMP_RESULT_OK           0
37#define PMP_RESULT_BADVERS      1
38#define PMP_RESULT_REFUSED      2
39#define PMP_RESULT_NETDOWN      3
40#define PMP_RESULT_NOMEM        4
41#define PMP_RESULT_BADOPCODE    5
42
43#define PMP_OPCODE_FROM_RESPONSE( op )  ( 0x80 ^ (op) )
44#define PMP_OPCODE_TO_RESPONSE( op )    ( 0x80 | (op) )
45#define PMP_OPCODE_IS_RESPONSE( op )    ( 0x80 & (op) )
46#define PMP_TOBUF16( buf, num ) ( *( (uint16_t *) (buf) ) = htons( (num) ) )
47#define PMP_TOBUF32( buf, num ) ( *( (uint32_t *) (buf) ) = htonl( (num) ) )
48#define PMP_FROMBUF16( buf )    ( htons( *( (uint16_t *) (buf) ) ) )
49#define PMP_FROMBUF32( buf )    ( htonl( *( (uint32_t *) (buf) ) ) )
50
51typedef struct tr_natpmp_uptime_s
52{
53    time_t   when;
54    uint32_t uptime;
55} tr_natpmp_uptime_t;
56
57typedef struct tr_natpmp_req_s
58{
59    unsigned int         adding : 1;
60    unsigned int         nobodyhome : 1;
61    unsigned int         tmpfail : 1;
62    int                  fd;
63    int                  delay;
64    uint64_t             retry;
65    uint64_t             timeout;
66    int                  askport;
67    int                  gotport;
68} tr_natpmp_req_t;
69
70struct tr_natpmp_s
71{
72#define PMP_STATE_IDLE          1
73#define PMP_STATE_ADDING        2
74#define PMP_STATE_DELETING      3
75#define PMP_STATE_MAPPED        4
76#define PMP_STATE_FAILED        5
77#define PMP_STATE_NOBODYHOME    6
78#define PMP_STATE_TMPFAIL       7
79    char               state;
80    unsigned int       active : 1;
81    unsigned int       mapped : 1;
82    struct in_addr     dest;
83    int                newport;
84    int                mappedport;
85    uint64_t           renew;
86    tr_natpmp_req_t *  req;
87    tr_natpmp_uptime_t uptime;
88    int                mcastfd;
89};
90
91typedef struct tr_natpmp_parse_s
92{
93    unsigned int tmpfail : 1;
94    uint32_t     seconds;
95    uint16_t     port;
96    uint32_t     lifetime;
97}
98tr_natpmp_parse_t;
99
100static int
101checktime( tr_natpmp_uptime_t * uptime, uint32_t seen );
102static void
103killsock( int * fd );
104static tr_natpmp_req_t *
105newreq( int adding, struct in_addr addr, int port );
106static void
107killreq( tr_natpmp_req_t ** req );
108static void
109resetreq( tr_natpmp_req_t * req );
110static tr_tristate_t
111pulsereq( tr_natpmp_t * req );
112static int
113sendreq( tr_natpmp_req_t * req );
114static int
115mcastsetup();
116static void
117mcastpulse( tr_natpmp_t * pmp );
118static tr_tristate_t
119parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse );
120
121tr_natpmp_t *
122tr_natpmpInit()
123{
124    tr_natpmp_t * pmp;
125
126    pmp = calloc( 1, sizeof( *pmp ) );
127    if( NULL == pmp )
128    {
129        return NULL;
130    }
131
132    pmp->state       = PMP_STATE_IDLE;
133    pmp->mcastfd     = -1;
134
135    if( tr_getDefaultRoute( &pmp->dest ) || INADDR_ANY == pmp->dest.s_addr )
136    {
137        pmp->dest.s_addr = INADDR_NONE;
138    }
139
140    if( INADDR_NONE == pmp->dest.s_addr )
141    {
142        tr_dbg( "nat-pmp device is unknown" );
143    }
144    else
145    {
146        char addrstr[INET_ADDRSTRLEN];
147        tr_netNtop( &pmp->dest, addrstr, sizeof( addrstr ) );
148        tr_dbg( "nat-pmp device is %s", addrstr );
149    }
150
151    return pmp;
152}
153
154void
155tr_natpmpStart( tr_natpmp_t * pmp )
156{
157    if( !pmp->active )
158    {
159        tr_inf( "starting nat-pmp" );
160        pmp->active = 1;
161        if( 0 > pmp->mcastfd )
162        {
163            pmp->mcastfd = mcastsetup();
164        }
165    }
166}
167
168void
169tr_natpmpStop( tr_natpmp_t * pmp )
170{
171    if( pmp->active )
172    {
173        tr_inf( "stopping nat-pmp" );
174        pmp->active = 0;
175        killsock( &pmp->mcastfd );
176        switch( pmp->state )
177        {
178            case PMP_STATE_IDLE:
179                break;
180            case PMP_STATE_ADDING:
181                pmp->state = PMP_STATE_IDLE;
182                tr_dbg( "nat-pmp state add -> idle" );
183                if( NULL != pmp->req )
184                {
185                    pmp->mappedport = pmp->req->gotport;
186                    killreq( &pmp->req );
187                    pmp->state = PMP_STATE_DELETING;
188                    tr_dbg( "nat-pmp state idle -> del" );
189                }
190                break;
191            case PMP_STATE_DELETING:
192                break;
193            case PMP_STATE_MAPPED:
194                pmp->state = PMP_STATE_DELETING;
195                tr_dbg( "nat-pmp state mapped -> del" );
196                break;
197            case PMP_STATE_FAILED:
198            case PMP_STATE_NOBODYHOME:
199            case PMP_STATE_TMPFAIL:
200                break;
201            default:
202                assert( 0 );
203                break;
204        }
205    }
206}
207
208int
209tr_natpmpStatus( tr_natpmp_t * pmp )
210{
211    int ret;
212   
213    if( !pmp->active )
214    {
215        ret = ( PMP_STATE_DELETING == pmp->state ?
216                TR_NAT_TRAVERSAL_UNMAPPING : TR_NAT_TRAVERSAL_DISABLED );
217    }
218    else if( pmp->mapped )
219    {
220        ret = TR_NAT_TRAVERSAL_MAPPED;
221    }
222    else
223    {
224        switch( pmp->state )
225        {
226            case PMP_STATE_IDLE:
227            case PMP_STATE_ADDING:
228            case PMP_STATE_DELETING:
229                ret = TR_NAT_TRAVERSAL_MAPPING;
230                break;
231            case PMP_STATE_FAILED:
232            case PMP_STATE_TMPFAIL:
233                ret = TR_NAT_TRAVERSAL_ERROR;
234                break;
235            case PMP_STATE_NOBODYHOME:
236                ret = TR_NAT_TRAVERSAL_NOTFOUND;
237                break;
238            case PMP_STATE_MAPPED:
239            default:
240                /* if pmp->state is PMP_STATE_MAPPED then pmp->mapped
241                   should be true */
242                assert( 0 );
243                ret = TR_NAT_TRAVERSAL_ERROR;
244                break;
245        }
246    }
247
248    return ret;
249}
250
251void
252tr_natpmpForwardPort( tr_natpmp_t * pmp, int port )
253{
254    tr_inf( "nat-pmp set port %i", port );
255    pmp->newport = port;
256}
257
258void
259tr_natpmpClose( tr_natpmp_t * pmp )
260{
261    /* try to send at least one delete request if we have a port mapping */
262    tr_natpmpStop( pmp );
263    tr_natpmpPulse( pmp, NULL );
264
265    killreq( &pmp->req );
266    free( pmp );
267}
268
269void
270tr_natpmpPulse( tr_natpmp_t * pmp, int * publicPort )
271{
272    if( 0 <= pmp->mcastfd )
273    {
274        mcastpulse( pmp );
275    }
276
277    if( pmp->active || PMP_STATE_DELETING == pmp->state )
278    {
279        switch( pmp->state )
280        {
281            case PMP_STATE_IDLE:
282            case PMP_STATE_TMPFAIL:
283                if( 0 < pmp->newport )
284                {
285                    tr_dbg( "nat-pmp state %s -> add with port %i",
286                            ( PMP_STATE_IDLE == pmp->state ? "idle" : "err" ),
287                            pmp->newport );
288                    pmp->state = PMP_STATE_ADDING;
289                }
290                break;
291
292            case PMP_STATE_ADDING:
293                if( NULL == pmp->req )
294                {
295                    if( 0 >= pmp->newport )
296                    {
297                        tr_dbg( "nat-pmp state add -> idle, no port" );
298                        pmp->state = PMP_STATE_IDLE;
299                    }
300                    else if( INADDR_NONE == pmp->dest.s_addr )
301                    {
302                        tr_dbg( "nat-pmp state add -> fail, no default route" );
303                        pmp->state = PMP_STATE_FAILED;
304                    }
305                    else
306                    {
307                        pmp->req = newreq( 1, pmp->dest, pmp->newport );
308                        if( NULL == pmp->req )
309                        {
310                            pmp->state = PMP_STATE_FAILED;
311                            tr_dbg( "nat-pmp state add -> fail on req init" );
312                        }
313                    }
314                }
315                if( PMP_STATE_ADDING == pmp->state )
316                {
317                    switch( pulsereq( pmp ) )
318                    {
319                        case TR_NET_ERROR:
320                            if( pmp->req->nobodyhome )
321                            {
322                                pmp->state = PMP_STATE_NOBODYHOME;
323                                tr_dbg( "nat-pmp state add -> nobodyhome on pulse" );
324                            }
325                            else if( pmp->req->tmpfail )
326                            {
327                                pmp->state = PMP_STATE_TMPFAIL;
328                                tr_dbg( "nat-pmp state add -> err on pulse" );
329                                if( pmp->req->askport == pmp->newport )
330                                {
331                                    pmp->newport = 0;
332                                }
333                            }
334                            else
335                            {
336                                pmp->state = PMP_STATE_FAILED;
337                                tr_dbg( "nat-pmp state add -> fail on pulse" );
338                            }
339                            killreq( &pmp->req );
340                            break;
341                        case TR_NET_OK:
342                            pmp->mappedport = pmp->req->gotport;
343                            if( pmp->mappedport != pmp->newport &&
344                                pmp->newport == pmp->req->askport )
345                            {
346                                pmp->newport = pmp->req->gotport;
347                            }
348                            killreq( &pmp->req );
349                            pmp->state = PMP_STATE_MAPPED;
350                            pmp->mapped = 1;
351                            tr_dbg( "nat-pmp state add -> mapped with port %i",
352                                    pmp->mappedport);
353                            tr_inf( "nat-pmp mapped port %i", pmp->mappedport );
354                            break;
355                        case TR_NET_WAIT:
356                            break;
357                    }
358                }
359                break;
360
361            case PMP_STATE_DELETING:
362                if( NULL == pmp->req )
363                {
364                    assert( 0 < pmp->mappedport );
365                    pmp->req = newreq( 0, pmp->dest, pmp->mappedport );
366                    if( NULL == pmp->req )
367                    {
368                        pmp->state = PMP_STATE_FAILED;
369                        tr_dbg( "nat-pmp state del -> fail on req init" );
370                    }
371                }
372                if( PMP_STATE_DELETING == pmp->state )
373                {
374                    switch( pulsereq( pmp ) )
375                    {
376                        case TR_NET_ERROR:
377                            if( pmp->req->nobodyhome )
378                            {
379                                pmp->mapped = 0;
380                                pmp->state = PMP_STATE_NOBODYHOME;
381                                tr_dbg( "nat-pmp state del -> nobodyhome on pulse" );
382                            }
383                            else if( pmp->req->tmpfail )
384                            {
385                                pmp->mapped = 0;
386                                pmp->state = PMP_STATE_TMPFAIL;
387                                tr_dbg( "nat-pmp state del -> err on pulse" );
388                                pmp->mappedport = -1;
389                            }
390                            else
391                            {
392                                pmp->state = PMP_STATE_FAILED;
393                                tr_dbg( "nat-pmp state del -> fail on pulse" );
394                            }
395                            killreq( &pmp->req );
396                            break;
397                        case TR_NET_OK:
398                            tr_dbg( "nat-pmp state del -> idle with port %i",
399                                    pmp->req->askport);
400                            tr_inf( "nat-pmp unmapped port %i",
401                                    pmp->req->askport );
402                            pmp->mapped = 0;
403                            pmp->mappedport = -1;
404                            killreq( &pmp->req );
405                            pmp->state = PMP_STATE_IDLE;
406                            break;
407                        case TR_NET_WAIT:
408                            break;
409                    }
410                }
411                break;
412
413            case PMP_STATE_MAPPED:
414                if( pmp->newport != pmp->mappedport )
415                {
416                    tr_dbg( "nat-pmp state mapped -> del, port from %i to %i",
417                            pmp->mappedport, pmp->newport );
418                    pmp->state = PMP_STATE_DELETING;
419                }
420                else if( tr_date() > pmp->renew )
421                {
422                    pmp->state = PMP_STATE_ADDING;
423                    tr_dbg( "nat-pmp state mapped -> add for renewal" );
424                }
425                break;
426
427            case PMP_STATE_FAILED:
428            case PMP_STATE_NOBODYHOME:
429                break;
430
431            default:
432                assert( 0 );
433                break;
434        }
435    }
436
437    if( NULL != publicPort )
438    {
439        *publicPort = -1;
440    }
441}
442
443static int
444checktime( tr_natpmp_uptime_t * uptime, uint32_t cursecs )
445{
446    time_t   now;
447    int      ret;
448    uint32_t estimated;
449
450    now = time( NULL );
451    ret = 0;
452    if( 0 < uptime->when )
453    {
454        estimated = ( ( now - uptime->when ) * 7 / 8 ) + uptime->uptime;
455        if( estimated > cursecs )
456        {
457            ret = 1;
458        }
459    }
460
461    uptime->when   = now;
462    uptime->uptime = cursecs;
463
464    return ret;
465}
466
467static void
468killsock( int * fd )
469{
470    if( 0 <= *fd )
471    {
472        tr_netClose( *fd );
473        *fd = -1;
474    }
475}
476
477static tr_natpmp_req_t *
478newreq( int adding, struct in_addr addr, int port )
479{
480    tr_natpmp_req_t * ret;
481
482    ret = calloc( 1, sizeof( *ret ) );
483    if( NULL == ret )
484    {
485        return NULL;
486    }
487
488    ret->fd = tr_netOpenUDP( addr, htons( PMP_PORT ), 1 );
489    if( 0 > ret->fd )
490    {
491        free( ret );
492        return NULL;
493    }
494
495    ret->adding  = adding;
496    ret->askport = port;
497    ret->gotport = port;
498    resetreq( ret );
499    if( sendreq( ret ) )
500    {
501        killreq( &ret );
502        return NULL;
503    }
504
505    return ret;
506}
507
508static void
509killreq( tr_natpmp_req_t ** req )
510{
511    if( NULL != *req )
512    {
513        killsock( &(*req)->fd );
514        free( *req );
515        *req = NULL;
516    }
517}
518
519static void
520resetreq( tr_natpmp_req_t * req )
521{
522    uint64_t now;
523
524    now          = tr_date();
525    req->delay   = PMP_INITIAL_DELAY;
526    req->retry   = now;
527    req->timeout = now + PMP_TOTAL_DELAY;
528}
529
530static tr_tristate_t
531pulsereq( tr_natpmp_t * pmp )
532{
533    tr_natpmp_req_t  * req = pmp->req;
534    struct sockaddr_in sin;
535    uint8_t            buf[16];
536    int                res;
537    uint64_t           now;
538    tr_tristate_t      ret;
539    tr_natpmp_parse_t  parse;
540
541    now = tr_date();
542    /* check for timeout */
543    if( now >= req->timeout )
544    {
545        tr_dbg( "nat-pmp request timed out" );
546        req->nobodyhome = 1;
547        return TR_NET_ERROR;
548    }
549    /* send another request  if it's been long enough */
550    if( now >= req->retry && sendreq( req ) )
551    {
552        return TR_NET_ERROR;
553    }
554
555    /* check for incoming packets */
556    res = tr_netRecvFrom( req->fd, buf, sizeof( buf ), &sin );
557    if( TR_NET_BLOCK & res )
558    {
559        return TR_NET_WAIT;
560    }
561    else if( TR_NET_CLOSE & res )
562    {
563        if( ECONNRESET == errno || ECONNREFUSED == errno )
564        {
565            tr_dbg( "nat-pmp not supported by device" );
566            req->nobodyhome = 1;
567        }
568        else
569        {
570            tr_inf( "error reading nat-pmp response (%s)", strerror( errno ) );
571        }
572        return TR_NET_ERROR;
573    }
574
575    /* parse the packet */
576    tr_dbg( "nat-pmp read %i byte response", res );
577    ret = parseresponse( buf, res, req->askport, &parse );
578    req->tmpfail = parse.tmpfail;
579    /* check for device reset */
580    if( checktime( &pmp->uptime, parse.seconds ) )
581    {
582        pmp->renew = 0;
583        tr_inf( "detected nat-pmp device reset" );
584        resetreq( req );
585        ret = TR_NET_WAIT;
586    }
587    if( TR_NET_OK == ret && req->adding )
588    {
589        if( req->askport != parse.port )
590        {
591            tr_dbg( "nat-pmp received %i for public port instead of %i",
592                    parse.port, req->askport );
593            req->gotport = parse.port;
594        }
595        tr_dbg( "nat-pmp set renew to half of %u", parse.lifetime );
596        pmp->renew = now + ( parse.lifetime / 2 * 1000 );
597    }
598
599    return ret;
600}
601
602static int
603sendreq( tr_natpmp_req_t * req )
604{
605    uint8_t buf[12];
606    int res;
607
608    bzero( buf, sizeof( buf ) );
609    buf[0] = PMP_VERSION;
610    buf[1] = PMP_OPCODE_ADDTCP;
611    PMP_TOBUF16( buf + 4, req->askport );
612    if( req->adding )
613    {
614        PMP_TOBUF16( buf + 6, req->askport );
615        PMP_TOBUF32( buf + 8, PMP_LIFETIME );
616    }
617
618    res = tr_netSend( req->fd, buf, sizeof( buf ) );
619    if( TR_NET_CLOSE & res && EHOSTUNREACH == errno )
620    {
621        res = TR_NET_BLOCK;
622    }
623    if( TR_NET_CLOSE & res )
624    {
625        tr_err( "failed to send nat-pmp request (%s)", strerror( errno ) );
626        return 1;
627    }
628    else if( !( TR_NET_BLOCK & res ) )
629    {
630        /* XXX is it all right to assume the entire thing is written? */
631        req->retry  = tr_date() + req->delay;
632        req->delay *= 2;
633    }
634    return 0;
635}
636
637static int
638mcastsetup()
639{
640    int fd;
641    struct in_addr addr;
642
643    addr.s_addr = inet_addr( PMP_MCAST_ADDR );
644    fd = tr_netMcastOpen( PMP_PORT, addr );
645    if( 0 > fd )
646    {
647        return -1;
648    }
649
650    tr_dbg( "nat-pmp create multicast socket %i", fd );
651
652    return fd;
653}
654
655static void
656mcastpulse( tr_natpmp_t * pmp )
657{
658    struct sockaddr_in sin;
659    uint8_t            buf[16];
660    int                res;
661    char               dbgstr[INET_ADDRSTRLEN];
662    tr_natpmp_parse_t  parse;
663
664    res = tr_netRecvFrom( pmp->mcastfd, buf, sizeof( buf ), &sin );
665    if( TR_NET_BLOCK & res )
666    {
667        return;
668    }
669    else if( TR_NET_CLOSE & res )
670    {
671        tr_err( "error reading nat-pmp multicast message" );
672        killsock( &pmp->mcastfd );
673        return;
674    }
675
676    tr_netNtop( &sin.sin_addr, dbgstr, sizeof( dbgstr ) );
677    tr_dbg( "nat-pmp read %i byte multicast packet from %s", res, dbgstr );
678
679    if( pmp->dest.s_addr != sin.sin_addr.s_addr )
680    {
681        tr_dbg( "nat-pmp ignoring multicast packet from unknown host %s",
682                dbgstr );
683        return;
684    }
685
686    if( TR_NET_OK == parseresponse( buf, res, -1, &parse ) )
687    {
688        if( checktime( &pmp->uptime, parse.seconds ) )
689        {
690            pmp->renew = 0;
691            tr_inf( "detected nat-pmp device reset" );
692            if( NULL != pmp->req )
693            {
694                resetreq( pmp->req );
695            }
696        }
697        if( PMP_STATE_NOBODYHOME == pmp->state )
698        {
699            tr_dbg( "nat-pmp state notfound -> idle" );
700            pmp->state = PMP_STATE_IDLE;
701        }
702    }
703}
704
705static tr_tristate_t
706parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse )
707{
708    int version, respopcode, opcode, wantedopcode, rescode, privport;
709
710    bzero( parse, sizeof( *parse ) );
711
712    if( 8 > len )
713    {
714        tr_err( "read truncated %i byte nat-pmp response packet", len );
715        return TR_NET_ERROR;
716    }
717
718    /* parse the first 8 bytes: version, opcode, and result code */
719    version      = buf[0];
720    respopcode   = buf[1];
721    opcode       = PMP_OPCODE_FROM_RESPONSE( respopcode );
722    wantedopcode = ( 0 < port ? PMP_OPCODE_ADDTCP : PMP_OPCODE_GETIP );
723    rescode      = PMP_FROMBUF16( buf + 2 );
724
725    if( PMP_VERSION != version )
726    {
727        tr_err( "unknown nat-pmp version %hhu", buf[0] );
728        return TR_NET_ERROR;
729    }
730    if( !PMP_OPCODE_IS_RESPONSE( respopcode ) )
731    {
732        tr_dbg( "nat-pmp ignoring request packet" );
733        return TR_NET_WAIT;
734    }
735    if( wantedopcode != opcode )
736    {
737        tr_err( "unknown nat-pmp opcode %hhu", opcode );
738        return TR_NET_ERROR;
739    }
740
741    switch( rescode )
742    {
743        case PMP_RESULT_OK:
744            break;
745        case PMP_RESULT_REFUSED:
746            tr_err( "nat-pmp mapping failed: refused/unauthorized/disabled" );
747            parse->tmpfail = 1;
748            return TR_NET_ERROR;
749        case PMP_RESULT_NETDOWN:
750            tr_err( "nat-pmp mapping failed: network down" );
751            parse->tmpfail = 1;
752            return TR_NET_ERROR;
753        case PMP_RESULT_NOMEM:
754            tr_err( "nat-pmp mapping refused: insufficient resources" );
755            parse->tmpfail = 1;
756            return TR_NET_ERROR;
757        default:
758            tr_err( "nat-pmp mapping refused: unknown result code: %hu",
759                    rescode );
760            return TR_NET_ERROR;
761    }
762
763    parse->seconds = PMP_FROMBUF32( buf + 4 );
764    if( PMP_OPCODE_ADDTCP == opcode )
765    {
766        if( 16 > len )
767        {
768            tr_err( "read truncated %i byte nat-pmp response packet", len );
769            return TR_NET_ERROR;
770        }
771        privport        = PMP_FROMBUF16( buf + 8 );
772        parse->port     = PMP_FROMBUF16( buf + 10 );
773        parse->lifetime = PMP_FROMBUF32( buf + 12 );
774
775        if( port != privport )
776        {
777            tr_dbg( "nat-pmp ignoring message for port %i, expected port %i",
778                    privport, port );
779            return TR_NET_WAIT;
780        }
781    }
782
783    return TR_NET_OK;
784}
Note: See TracBrowser for help on using the repository browser.