source: trunk/libtransmission/natpmp.c @ 1725

Last change on this file since 1725 was 1725, checked in by joshe, 16 years ago

Fix port crap.

  • Property svn:keywords set to Date Rev Author Id
File size: 22.5 KB
Line 
1/******************************************************************************
2 * $Id: natpmp.c 1725 2007-04-16 05:48:52Z 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 void
101unmap( tr_natpmp_t * pmp );
102static int
103checktime( tr_natpmp_uptime_t * uptime, uint32_t seen );
104static void
105killsock( int * fd );
106static tr_natpmp_req_t *
107newreq( int adding, struct in_addr addr, int port );
108static void
109killreq( tr_natpmp_req_t ** req );
110static void
111resetreq( tr_natpmp_req_t * req );
112static tr_tristate_t
113pulsereq( tr_natpmp_t * req );
114static int
115sendreq( tr_natpmp_req_t * req );
116static int
117mcastsetup();
118static void
119mcastpulse( tr_natpmp_t * pmp );
120static tr_tristate_t
121parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse );
122
123tr_natpmp_t *
124tr_natpmpInit()
125{
126    tr_natpmp_t * pmp;
127
128    pmp = calloc( 1, sizeof( *pmp ) );
129    if( NULL == pmp )
130    {
131        return NULL;
132    }
133
134    pmp->state       = PMP_STATE_IDLE;
135    pmp->mcastfd     = -1;
136
137    if( tr_getDefaultRoute( &pmp->dest ) || INADDR_ANY == pmp->dest.s_addr )
138    {
139        pmp->dest.s_addr = INADDR_NONE;
140    }
141
142    if( INADDR_NONE == pmp->dest.s_addr )
143    {
144        tr_dbg( "nat-pmp device is unknown" );
145    }
146    else
147    {
148        char addrstr[INET_ADDRSTRLEN];
149        tr_netNtop( &pmp->dest, addrstr, sizeof( addrstr ) );
150        tr_dbg( "nat-pmp device is %s", addrstr );
151    }
152
153    return pmp;
154}
155
156void
157tr_natpmpStart( tr_natpmp_t * pmp )
158{
159    if( !pmp->active )
160    {
161        tr_inf( "starting nat-pmp" );
162        pmp->active = 1;
163        if( 0 > pmp->mcastfd )
164        {
165            pmp->mcastfd = mcastsetup();
166        }
167    }
168}
169
170void
171tr_natpmpStop( tr_natpmp_t * pmp )
172{
173    if( pmp->active )
174    {
175        tr_inf( "stopping nat-pmp" );
176        pmp->active = 0;
177        killsock( &pmp->mcastfd );
178        unmap( pmp );
179    }
180}
181
182int
183tr_natpmpStatus( tr_natpmp_t * pmp )
184{
185    int ret;
186   
187    if( !pmp->active )
188    {
189        ret = ( PMP_STATE_DELETING == pmp->state ?
190                TR_NAT_TRAVERSAL_UNMAPPING : TR_NAT_TRAVERSAL_DISABLED );
191    }
192    else if( pmp->mapped )
193    {
194        ret = TR_NAT_TRAVERSAL_MAPPED;
195    }
196    else
197    {
198        switch( pmp->state )
199        {
200            case PMP_STATE_IDLE:
201            case PMP_STATE_ADDING:
202            case PMP_STATE_DELETING:
203                ret = TR_NAT_TRAVERSAL_MAPPING;
204                break;
205            case PMP_STATE_FAILED:
206            case PMP_STATE_TMPFAIL:
207                ret = TR_NAT_TRAVERSAL_ERROR;
208                break;
209            case PMP_STATE_NOBODYHOME:
210                ret = TR_NAT_TRAVERSAL_NOTFOUND;
211                break;
212            case PMP_STATE_MAPPED:
213            default:
214                /* if pmp->state is PMP_STATE_MAPPED then pmp->mapped
215                   should be true */
216                assert( 0 );
217                ret = TR_NAT_TRAVERSAL_ERROR;
218                break;
219        }
220    }
221
222    return ret;
223}
224
225void
226tr_natpmpForwardPort( tr_natpmp_t * pmp, int port )
227{
228    tr_inf( "nat-pmp set port %i", port );
229    pmp->newport = port;
230}
231
232void
233tr_natpmpRemoveForwarding( tr_natpmp_t * pmp )
234{
235    tr_inf( "nat-pmp unset port" );
236    pmp->newport = -1;
237    unmap( pmp );
238}
239
240void
241tr_natpmpClose( tr_natpmp_t * pmp )
242{
243    /* try to send at least one delete request if we have a port mapping */
244    tr_natpmpStop( pmp );
245    tr_natpmpPulse( pmp, NULL );
246
247    killreq( &pmp->req );
248    free( pmp );
249}
250
251void
252tr_natpmpPulse( tr_natpmp_t * pmp, int * publicPort )
253{
254    if( 0 <= pmp->mcastfd )
255    {
256        mcastpulse( pmp );
257    }
258
259    if( pmp->active || PMP_STATE_DELETING == pmp->state )
260    {
261        switch( pmp->state )
262        {
263            case PMP_STATE_IDLE:
264            case PMP_STATE_TMPFAIL:
265                if( 0 < pmp->newport )
266                {
267                    tr_dbg( "nat-pmp state %s -> add with port %i",
268                            ( PMP_STATE_IDLE == pmp->state ? "idle" : "err" ),
269                            pmp->newport );
270                    pmp->state = PMP_STATE_ADDING;
271                }
272                break;
273
274            case PMP_STATE_ADDING:
275                if( NULL == pmp->req )
276                {
277                    if( 0 >= pmp->newport )
278                    {
279                        tr_dbg( "nat-pmp state add -> idle, no port" );
280                        pmp->state = PMP_STATE_IDLE;
281                    }
282                    else if( INADDR_NONE == pmp->dest.s_addr )
283                    {
284                        tr_dbg( "nat-pmp state add -> fail, no default route" );
285                        pmp->state = PMP_STATE_FAILED;
286                    }
287                    else
288                    {
289                        pmp->req = newreq( 1, pmp->dest, pmp->newport );
290                        if( NULL == pmp->req )
291                        {
292                            pmp->state = PMP_STATE_FAILED;
293                            tr_dbg( "nat-pmp state add -> fail on req init" );
294                        }
295                    }
296                }
297                if( PMP_STATE_ADDING == pmp->state )
298                {
299                    switch( pulsereq( pmp ) )
300                    {
301                        case TR_NET_ERROR:
302                            if( pmp->req->nobodyhome )
303                            {
304                                pmp->state = PMP_STATE_NOBODYHOME;
305                                tr_dbg( "nat-pmp state add -> nobodyhome on pulse" );
306                            }
307                            else if( pmp->req->tmpfail )
308                            {
309                                pmp->state = PMP_STATE_TMPFAIL;
310                                tr_dbg( "nat-pmp state add -> err on pulse" );
311                                if( pmp->req->askport == pmp->newport )
312                                {
313                                    pmp->newport = 0;
314                                }
315                            }
316                            else
317                            {
318                                pmp->state = PMP_STATE_FAILED;
319                                tr_dbg( "nat-pmp state add -> fail on pulse" );
320                            }
321                            killreq( &pmp->req );
322                            break;
323                        case TR_NET_OK:
324                            pmp->mappedport = pmp->req->gotport;
325                            if( pmp->mappedport != pmp->newport &&
326                                pmp->newport == pmp->req->askport )
327                            {
328                                pmp->newport = pmp->req->gotport;
329                            }
330                            killreq( &pmp->req );
331                            pmp->state = PMP_STATE_MAPPED;
332                            pmp->mapped = 1;
333                            tr_dbg( "nat-pmp state add -> mapped with port %i",
334                                    pmp->mappedport);
335                            tr_inf( "nat-pmp mapped port %i", pmp->mappedport );
336                            if( NULL != publicPort )
337                            {
338                                *publicPort = pmp->mappedport;
339                            }
340                            break;
341                        case TR_NET_WAIT:
342                            break;
343                    }
344                }
345                break;
346
347            case PMP_STATE_DELETING:
348                if( NULL == pmp->req )
349                {
350                    assert( 0 < pmp->mappedport );
351                    pmp->req = newreq( 0, pmp->dest, pmp->mappedport );
352                    if( NULL == pmp->req )
353                    {
354                        pmp->state = PMP_STATE_FAILED;
355                        tr_dbg( "nat-pmp state del -> fail on req init" );
356                    }
357                }
358                if( PMP_STATE_DELETING == pmp->state )
359                {
360                    switch( pulsereq( pmp ) )
361                    {
362                        case TR_NET_ERROR:
363                            if( pmp->req->nobodyhome )
364                            {
365                                pmp->mapped = 0;
366                                pmp->state = PMP_STATE_NOBODYHOME;
367                                tr_dbg( "nat-pmp state del -> nobodyhome on pulse" );
368                            }
369                            else if( pmp->req->tmpfail )
370                            {
371                                pmp->mapped = 0;
372                                pmp->state = PMP_STATE_TMPFAIL;
373                                tr_dbg( "nat-pmp state del -> err on pulse" );
374                                pmp->mappedport = -1;
375                            }
376                            else
377                            {
378                                pmp->state = PMP_STATE_FAILED;
379                                tr_dbg( "nat-pmp state del -> fail on pulse" );
380                            }
381                            killreq( &pmp->req );
382                            break;
383                        case TR_NET_OK:
384                            tr_dbg( "nat-pmp state del -> idle with port %i",
385                                    pmp->req->askport);
386                            tr_inf( "nat-pmp unmapped port %i",
387                                    pmp->req->askport );
388                            pmp->mapped = 0;
389                            pmp->mappedport = -1;
390                            killreq( &pmp->req );
391                            pmp->state = PMP_STATE_IDLE;
392                            break;
393                        case TR_NET_WAIT:
394                            break;
395                    }
396                }
397                break;
398
399            case PMP_STATE_MAPPED:
400                if( pmp->newport != pmp->mappedport )
401                {
402                    tr_dbg( "nat-pmp state mapped -> del, port from %i to %i",
403                            pmp->mappedport, pmp->newport );
404                    pmp->state = PMP_STATE_DELETING;
405                }
406                else if( tr_date() > pmp->renew )
407                {
408                    pmp->state = PMP_STATE_ADDING;
409                    tr_dbg( "nat-pmp state mapped -> add for renewal" );
410                }
411                break;
412
413            case PMP_STATE_FAILED:
414            case PMP_STATE_NOBODYHOME:
415                break;
416
417            default:
418                assert( 0 );
419                break;
420        }
421    }
422
423    if( NULL != publicPort )
424    {
425        *publicPort = -1;
426    }
427}
428
429void
430unmap( tr_natpmp_t * pmp )
431{
432    switch( pmp->state )
433    {
434        case PMP_STATE_IDLE:
435            break;
436        case PMP_STATE_ADDING:
437            if( NULL == pmp->req )
438            {
439                pmp->state = PMP_STATE_IDLE;
440                tr_dbg( "nat-pmp state add -> idle" );
441            }
442            else
443            {
444                pmp->mappedport = pmp->req->gotport;
445                killreq( &pmp->req );
446                pmp->state = PMP_STATE_DELETING;
447                tr_dbg( "nat-pmp state add -> del" );
448            }
449            break;
450        case PMP_STATE_DELETING:
451            break;
452        case PMP_STATE_MAPPED:
453            pmp->state = PMP_STATE_DELETING;
454            tr_dbg( "nat-pmp state mapped -> del" );
455            break;
456        case PMP_STATE_FAILED:
457        case PMP_STATE_NOBODYHOME:
458        case PMP_STATE_TMPFAIL:
459            break;
460        default:
461            assert( 0 );
462            break;
463    }
464}
465
466static int
467checktime( tr_natpmp_uptime_t * uptime, uint32_t cursecs )
468{
469    time_t   now;
470    int      ret;
471    uint32_t estimated;
472
473    now = time( NULL );
474    ret = 0;
475    if( 0 < uptime->when )
476    {
477        estimated = ( ( now - uptime->when ) * 7 / 8 ) + uptime->uptime;
478        if( estimated > cursecs )
479        {
480            ret = 1;
481        }
482    }
483
484    uptime->when   = now;
485    uptime->uptime = cursecs;
486
487    return ret;
488}
489
490static void
491killsock( int * fd )
492{
493    if( 0 <= *fd )
494    {
495        tr_netClose( *fd );
496        *fd = -1;
497    }
498}
499
500static tr_natpmp_req_t *
501newreq( int adding, struct in_addr addr, int port )
502{
503    tr_natpmp_req_t * ret;
504
505    ret = calloc( 1, sizeof( *ret ) );
506    if( NULL == ret )
507    {
508        return NULL;
509    }
510
511    ret->fd = tr_netOpenUDP( addr, htons( PMP_PORT ), 1 );
512    if( 0 > ret->fd )
513    {
514        free( ret );
515        return NULL;
516    }
517
518    ret->adding  = adding;
519    ret->askport = port;
520    ret->gotport = port;
521    resetreq( ret );
522    if( sendreq( ret ) )
523    {
524        killreq( &ret );
525        return NULL;
526    }
527
528    return ret;
529}
530
531static void
532killreq( tr_natpmp_req_t ** req )
533{
534    if( NULL != *req )
535    {
536        killsock( &(*req)->fd );
537        free( *req );
538        *req = NULL;
539    }
540}
541
542static void
543resetreq( tr_natpmp_req_t * req )
544{
545    uint64_t now;
546
547    now          = tr_date();
548    req->delay   = PMP_INITIAL_DELAY;
549    req->retry   = now;
550    req->timeout = now + PMP_TOTAL_DELAY;
551}
552
553static tr_tristate_t
554pulsereq( tr_natpmp_t * pmp )
555{
556    tr_natpmp_req_t  * req = pmp->req;
557    struct sockaddr_in sin;
558    uint8_t            buf[16];
559    int                res;
560    uint64_t           now;
561    tr_tristate_t      ret;
562    tr_natpmp_parse_t  parse;
563
564    now = tr_date();
565    /* check for timeout */
566    if( now >= req->timeout )
567    {
568        tr_dbg( "nat-pmp request timed out" );
569        req->nobodyhome = 1;
570        return TR_NET_ERROR;
571    }
572    /* send another request  if it's been long enough */
573    if( now >= req->retry && sendreq( req ) )
574    {
575        return TR_NET_ERROR;
576    }
577
578    /* check for incoming packets */
579    res = tr_netRecvFrom( req->fd, buf, sizeof( buf ), &sin );
580    if( TR_NET_BLOCK & res )
581    {
582        return TR_NET_WAIT;
583    }
584    else if( TR_NET_CLOSE & res )
585    {
586        if( ECONNRESET == errno || ECONNREFUSED == errno )
587        {
588            tr_dbg( "nat-pmp not supported by device" );
589            req->nobodyhome = 1;
590        }
591        else
592        {
593            tr_inf( "error reading nat-pmp response (%s)", strerror( errno ) );
594        }
595        return TR_NET_ERROR;
596    }
597
598    /* parse the packet */
599    tr_dbg( "nat-pmp read %i byte response", res );
600    ret = parseresponse( buf, res, req->askport, &parse );
601    req->tmpfail = parse.tmpfail;
602    /* check for device reset */
603    if( checktime( &pmp->uptime, parse.seconds ) )
604    {
605        pmp->renew = 0;
606        tr_inf( "detected nat-pmp device reset" );
607        resetreq( req );
608        ret = TR_NET_WAIT;
609    }
610    if( TR_NET_OK == ret && req->adding )
611    {
612        if( req->askport != parse.port )
613        {
614            tr_dbg( "nat-pmp received %i for public port instead of %i",
615                    parse.port, req->askport );
616            req->gotport = parse.port;
617        }
618        tr_dbg( "nat-pmp set renew to half of %u", parse.lifetime );
619        pmp->renew = now + ( parse.lifetime / 2 * 1000 );
620    }
621
622    return ret;
623}
624
625static int
626sendreq( tr_natpmp_req_t * req )
627{
628    uint8_t buf[12];
629    int res;
630
631    memset( buf, 0, sizeof( buf ) );
632    buf[0] = PMP_VERSION;
633    buf[1] = PMP_OPCODE_ADDTCP;
634    PMP_TOBUF16( buf + 4, req->askport );
635    if( req->adding )
636    {
637        PMP_TOBUF16( buf + 6, req->askport );
638        PMP_TOBUF32( buf + 8, PMP_LIFETIME );
639    }
640
641    res = tr_netSend( req->fd, buf, sizeof( buf ) );
642    if( TR_NET_CLOSE & res && EHOSTUNREACH == errno )
643    {
644        res = TR_NET_BLOCK;
645    }
646    if( TR_NET_CLOSE & res )
647    {
648        tr_err( "failed to send nat-pmp request (%s)", strerror( errno ) );
649        return 1;
650    }
651    else if( !( TR_NET_BLOCK & res ) )
652    {
653        /* XXX is it all right to assume the entire thing is written? */
654        req->retry  = tr_date() + req->delay;
655        req->delay *= 2;
656    }
657    return 0;
658}
659
660static int
661mcastsetup()
662{
663    int fd;
664    struct in_addr addr;
665
666    addr.s_addr = inet_addr( PMP_MCAST_ADDR );
667    fd = tr_netMcastOpen( PMP_PORT, addr );
668    if( 0 > fd )
669    {
670        return -1;
671    }
672
673    tr_dbg( "nat-pmp create multicast socket %i", fd );
674
675    return fd;
676}
677
678static void
679mcastpulse( tr_natpmp_t * pmp )
680{
681    struct sockaddr_in sin;
682    uint8_t            buf[16];
683    int                res;
684    char               dbgstr[INET_ADDRSTRLEN];
685    tr_natpmp_parse_t  parse;
686
687    res = tr_netRecvFrom( pmp->mcastfd, buf, sizeof( buf ), &sin );
688    if( TR_NET_BLOCK & res )
689    {
690        return;
691    }
692    else if( TR_NET_CLOSE & res )
693    {
694        tr_err( "error reading nat-pmp multicast message" );
695        killsock( &pmp->mcastfd );
696        return;
697    }
698
699    tr_netNtop( &sin.sin_addr, dbgstr, sizeof( dbgstr ) );
700    tr_dbg( "nat-pmp read %i byte multicast packet from %s", res, dbgstr );
701
702    if( pmp->dest.s_addr != sin.sin_addr.s_addr )
703    {
704        tr_dbg( "nat-pmp ignoring multicast packet from unknown host %s",
705                dbgstr );
706        return;
707    }
708
709    if( TR_NET_OK == parseresponse( buf, res, -1, &parse ) )
710    {
711        if( checktime( &pmp->uptime, parse.seconds ) )
712        {
713            pmp->renew = 0;
714            tr_inf( "detected nat-pmp device reset" );
715            if( NULL != pmp->req )
716            {
717                resetreq( pmp->req );
718            }
719        }
720        if( PMP_STATE_NOBODYHOME == pmp->state )
721        {
722            tr_dbg( "nat-pmp state notfound -> idle" );
723            pmp->state = PMP_STATE_IDLE;
724        }
725    }
726}
727
728static tr_tristate_t
729parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse )
730{
731    int version, respopcode, opcode, wantedopcode, rescode, privport;
732
733    memset( parse, 0, sizeof( *parse ) );
734
735    if( 8 > len )
736    {
737        tr_err( "read truncated %i byte nat-pmp response packet", len );
738        return TR_NET_ERROR;
739    }
740
741    /* parse the first 8 bytes: version, opcode, and result code */
742    version      = buf[0];
743    respopcode   = buf[1];
744    opcode       = PMP_OPCODE_FROM_RESPONSE( respopcode );
745    wantedopcode = ( 0 < port ? PMP_OPCODE_ADDTCP : PMP_OPCODE_GETIP );
746    rescode      = PMP_FROMBUF16( buf + 2 );
747
748    if( PMP_VERSION != version )
749    {
750        tr_err( "unknown nat-pmp version %hhu", buf[0] );
751        return TR_NET_ERROR;
752    }
753    if( !PMP_OPCODE_IS_RESPONSE( respopcode ) )
754    {
755        tr_dbg( "nat-pmp ignoring request packet" );
756        return TR_NET_WAIT;
757    }
758    if( wantedopcode != opcode )
759    {
760        tr_err( "unknown nat-pmp opcode %hhu", opcode );
761        return TR_NET_ERROR;
762    }
763
764    switch( rescode )
765    {
766        case PMP_RESULT_OK:
767            break;
768        case PMP_RESULT_REFUSED:
769            tr_err( "nat-pmp mapping failed: refused/unauthorized/disabled" );
770            parse->tmpfail = 1;
771            return TR_NET_ERROR;
772        case PMP_RESULT_NETDOWN:
773            tr_err( "nat-pmp mapping failed: network down" );
774            parse->tmpfail = 1;
775            return TR_NET_ERROR;
776        case PMP_RESULT_NOMEM:
777            tr_err( "nat-pmp mapping refused: insufficient resources" );
778            parse->tmpfail = 1;
779            return TR_NET_ERROR;
780        default:
781            tr_err( "nat-pmp mapping refused: unknown result code: %hu",
782                    rescode );
783            return TR_NET_ERROR;
784    }
785
786    parse->seconds = PMP_FROMBUF32( buf + 4 );
787    if( PMP_OPCODE_ADDTCP == opcode )
788    {
789        if( 16 > len )
790        {
791            tr_err( "read truncated %i byte nat-pmp response packet", len );
792            return TR_NET_ERROR;
793        }
794        privport        = PMP_FROMBUF16( buf + 8 );
795        parse->port     = PMP_FROMBUF16( buf + 10 );
796        parse->lifetime = PMP_FROMBUF32( buf + 12 );
797
798        if( port != privport )
799        {
800            tr_dbg( "nat-pmp ignoring message for port %i, expected port %i",
801                    privport, port );
802            return TR_NET_WAIT;
803        }
804    }
805
806    return TR_NET_OK;
807}
Note: See TracBrowser for help on using the repository browser.