source: trunk/libtransmission/natpmp.c @ 1420

Last change on this file since 1420 was 1420, checked in by titer, 16 years ago

Officially give up on making libT reentrant, and simplify our code instead

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