| File: | libs/libnatpmp/natpmp.c |
| Location: | line 214, column 31 |
| Description: | The left operand of '!=' is a garbage value |
| 1 | /* $Id: natpmp.c,v 1.8 2008/07/02 22:33:06 nanard Exp $ */ | |||
| 2 | /* libnatpmp | |||
| 3 | * Copyright (c) 2007-2008, Thomas BERNARD <miniupnp@free.fr> | |||
| 4 | * http://miniupnp.free.fr/libnatpmp.html | |||
| 5 | * | |||
| 6 | * Permission to use, copy, modify, and/or distribute this software for any | |||
| 7 | * purpose with or without fee is hereby granted, provided that the above | |||
| 8 | * copyright notice and this permission notice appear in all copies. | |||
| 9 | * | |||
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | |||
| 17 | #ifdef __linux__1 | |||
| 18 | #ifndef _DEFAULT_SOURCE1 | |||
| 19 | #define _DEFAULT_SOURCE1 | |||
| 20 | #endif | |||
| 21 | #define _BSD_SOURCE1 1 | |||
| 22 | #endif | |||
| 23 | #include <string.h> | |||
| 24 | #include <time.h> | |||
| 25 | #ifndef _MSC_VER | |||
| 26 | #include <sys/time.h> | |||
| 27 | #endif | |||
| 28 | #ifdef WIN32 | |||
| 29 | #include <winsock2.h> | |||
| 30 | #include <Ws2tcpip.h> | |||
| 31 | #include <io.h> | |||
| 32 | #define EWOULDBLOCK11 WSAEWOULDBLOCK | |||
| 33 | #define ECONNREFUSED111 WSAECONNREFUSED | |||
| 34 | ||||
| 35 | static int gettimeofday(struct timeval* p, void* tz /* IGNORED */) { | |||
| 36 | union { | |||
| 37 | long long ns100; /*time since 1 Jan 1601 in 100ns units */ | |||
| 38 | FILETIME ft; | |||
| 39 | } _now; | |||
| 40 | ||||
| 41 | GetSystemTimeAsFileTime( &(_now.ft) ); | |||
| 42 | p->tv_usec=(long)((_now.ns100 / 10LL) % 1000000LL ); | |||
| 43 | p->tv_sec= (long)((_now.ns100-(116444736000000000LL))/10000000LL); | |||
| 44 | return 0; | |||
| 45 | } | |||
| 46 | ||||
| 47 | #else | |||
| 48 | #include <errno(*__errno_location ()).h> | |||
| 49 | #include <unistd.h> | |||
| 50 | #include <fcntl.h> | |||
| 51 | #include <sys/types.h> | |||
| 52 | #include <sys/socket.h> | |||
| 53 | #define closesocketclose close | |||
| 54 | #endif | |||
| 55 | #include "natpmp.h" | |||
| 56 | #include "getgateway.h" | |||
| 57 | ||||
| 58 | int initnatpmp(natpmp_t * p) | |||
| 59 | { | |||
| 60 | #ifdef WIN32 | |||
| 61 | u_long ioctlArg = 1; | |||
| 62 | #else | |||
| 63 | int flags; | |||
| 64 | #endif | |||
| 65 | struct sockaddr_in addr; | |||
| 66 | if(!p) | |||
| 67 | return NATPMP_ERR_INVALIDARGS(-1); | |||
| 68 | memset(p, 0, sizeof(natpmp_t)); | |||
| 69 | p->s = socket(PF_INET2, SOCK_DGRAMSOCK_DGRAM, 0); | |||
| 70 | if(p->s < 0) | |||
| 71 | return NATPMP_ERR_SOCKETERROR(-2); | |||
| 72 | #ifdef WIN32 | |||
| 73 | if(ioctlsocket(p->s, FIONBIO, &ioctlArg) == SOCKET_ERROR) | |||
| 74 | return NATPMP_ERR_FCNTLERROR(-11); | |||
| 75 | #else | |||
| 76 | if((flags = fcntl(p->s, F_GETFL3, 0)) < 0) | |||
| 77 | return NATPMP_ERR_FCNTLERROR(-11); | |||
| 78 | if(fcntl(p->s, F_SETFL4, flags | O_NONBLOCK04000) < 0) | |||
| 79 | return NATPMP_ERR_FCNTLERROR(-11); | |||
| 80 | #endif | |||
| 81 | ||||
| 82 | if(getdefaultgateway(&(p->gateway)) < 0) | |||
| 83 | return NATPMP_ERR_CANNOTGETGATEWAY(-3); | |||
| 84 | ||||
| 85 | memset(&addr, 0, sizeof(addr)); | |||
| 86 | addr.sin_family = AF_INET2; | |||
| 87 | addr.sin_port = htons(NATPMP_PORT)(__extension__ ({ unsigned short int __v, __x = (unsigned short int) ((5351)); if (__builtin_constant_p (__x)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff) | (((__x) & 0xff ) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc"); __v; })); | |||
| 88 | addr.sin_addr.s_addr = p->gateway; | |||
| 89 | if(connect(p->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) | |||
| 90 | return NATPMP_ERR_CONNECTERR(-8); | |||
| 91 | return 0; | |||
| 92 | } | |||
| 93 | ||||
| 94 | int closenatpmp(natpmp_t * p) | |||
| 95 | { | |||
| 96 | if(!p) | |||
| 97 | return NATPMP_ERR_INVALIDARGS(-1); | |||
| 98 | if(closesocketclose(p->s) < 0) | |||
| 99 | return NATPMP_ERR_CLOSEERR(-4); | |||
| 100 | return 0; | |||
| 101 | } | |||
| 102 | ||||
| 103 | int sendpendingrequest(natpmp_t * p) | |||
| 104 | { | |||
| 105 | int r; | |||
| 106 | /* struct sockaddr_in addr;*/ | |||
| 107 | if(!p) | |||
| 108 | return NATPMP_ERR_INVALIDARGS(-1); | |||
| 109 | /* memset(&addr, 0, sizeof(addr)); | |||
| 110 | addr.sin_family = AF_INET; | |||
| 111 | addr.sin_port = htons(NATPMP_PORT); | |||
| 112 | addr.sin_addr.s_addr = p->gateway; | |||
| 113 | r = (int)sendto(p->s, p->pending_request, p->pending_request_len, 0, | |||
| 114 | (struct sockaddr *)&addr, sizeof(addr));*/ | |||
| 115 | r = (int)send(p->s, p->pending_request, p->pending_request_len, 0); | |||
| 116 | return (r<0) ? NATPMP_ERR_SENDERR(-10) : r; | |||
| 117 | } | |||
| 118 | ||||
| 119 | int sendnatpmprequest(natpmp_t * p) | |||
| 120 | { | |||
| 121 | int n; | |||
| 122 | if(!p) | |||
| 123 | return NATPMP_ERR_INVALIDARGS(-1); | |||
| 124 | /* TODO : check if no request is allready pending */ | |||
| 125 | p->has_pending_request = 1; | |||
| 126 | p->try_number = 1; | |||
| 127 | n = sendpendingrequest(p); | |||
| 128 | gettimeofday(&p->retry_time, NULL((void*)0)); // check errors ! | |||
| 129 | p->retry_time.tv_usec += 250000; /* add 250ms */ | |||
| 130 | if(p->retry_time.tv_usec >= 1000000) { | |||
| 131 | p->retry_time.tv_usec -= 1000000; | |||
| 132 | p->retry_time.tv_sec++; | |||
| 133 | } | |||
| 134 | return n; | |||
| 135 | } | |||
| 136 | ||||
| 137 | int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout) | |||
| 138 | { | |||
| 139 | struct timeval now; | |||
| 140 | if(!p || !timeout) | |||
| 141 | return NATPMP_ERR_INVALIDARGS(-1); | |||
| 142 | if(!p->has_pending_request) | |||
| 143 | return NATPMP_ERR_NOPENDINGREQ(-6); | |||
| 144 | if(gettimeofday(&now, NULL((void*)0)) < 0) | |||
| 145 | return NATPMP_ERR_GETTIMEOFDAYERR(-12); | |||
| 146 | timeout->tv_sec = p->retry_time.tv_sec - now.tv_sec; | |||
| 147 | timeout->tv_usec = p->retry_time.tv_usec - now.tv_usec; | |||
| 148 | if(timeout->tv_usec < 0) { | |||
| 149 | timeout->tv_usec += 1000000; | |||
| 150 | timeout->tv_sec--; | |||
| 151 | } | |||
| 152 | return 0; | |||
| 153 | } | |||
| 154 | ||||
| 155 | int sendpublicaddressrequest(natpmp_t * p) | |||
| 156 | { | |||
| 157 | if(!p) | |||
| 158 | return NATPMP_ERR_INVALIDARGS(-1); | |||
| 159 | //static const unsigned char request[] = { 0, 0 }; | |||
| 160 | p->pending_request[0] = 0; | |||
| 161 | p->pending_request[1] = 0; | |||
| 162 | p->pending_request_len = 2; | |||
| 163 | // TODO: return 0 instead of sizeof(request) ?? | |||
| 164 | return sendnatpmprequest(p); | |||
| 165 | } | |||
| 166 | ||||
| 167 | int sendnewportmappingrequest(natpmp_t * p, int protocol, | |||
| 168 | uint16_t privateport, uint16_t publicport, | |||
| 169 | uint32_t lifetime) | |||
| 170 | { | |||
| 171 | uint16_t *n; | |||
| 172 | uint32_t *m; | |||
| 173 | ||||
| 174 | if(!p || (protocol!=NATPMP_PROTOCOL_TCP(2) && protocol!=NATPMP_PROTOCOL_UDP(1))) | |||
| 175 | return NATPMP_ERR_INVALIDARGS(-1); | |||
| 176 | p->pending_request[0] = 0; | |||
| 177 | p->pending_request[1] = (char)protocol; | |||
| 178 | p->pending_request[2] = 0; | |||
| 179 | p->pending_request[3] = 0; | |||
| 180 | n = (uint16_t *)(p->pending_request + 4); *n = htons(privateport)(__extension__ ({ unsigned short int __v, __x = (unsigned short int) (privateport); if (__builtin_constant_p (__x)) __v = (( unsigned short int) ((((__x) >> 8) & 0xff) | (((__x ) & 0xff) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc"); __v; })); | |||
| 181 | n = (uint16_t *)(p->pending_request + 6); *n = htons(publicport)(__extension__ ({ unsigned short int __v, __x = (unsigned short int) (publicport); if (__builtin_constant_p (__x)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff) | (((__x) & 0xff ) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc"); __v; })); | |||
| 182 | m = (uint32_t *)(p->pending_request + 8); *m = htonl(lifetime)(__extension__ ({ unsigned int __v, __x = (lifetime); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x ) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) << 24)); else __asm__ ( "bswap %0" : "=r" (__v) : "0" (__x)); __v; })); | |||
| 183 | ||||
| 184 | //*((uint16_t *)(p->pending_request + 4)) = htons(privateport); | |||
| 185 | //*((uint16_t *)(p->pending_request + 6)) = htons(publicport); | |||
| 186 | //*((uint32_t *)(p->pending_request + 8)) = htonl(lifetime); | |||
| 187 | p->pending_request_len = 12; | |||
| 188 | return sendnatpmprequest(p); | |||
| 189 | } | |||
| 190 | ||||
| 191 | int readnatpmpresponse(natpmp_t * p, natpmpresp_t * response) | |||
| 192 | { | |||
| 193 | unsigned char buf[16]; | |||
| 194 | struct sockaddr_in addr; | |||
| 195 | socklen_t addrlen = sizeof(addr); | |||
| 196 | int n; | |||
| 197 | if(!p) | |||
| 198 | return NATPMP_ERR_INVALIDARGS(-1); | |||
| 199 | n = recvfrom(p->s, (char *)buf, sizeof(buf), 0, | |||
| 200 | (struct sockaddr *)&addr, &addrlen); | |||
| 201 | if(n<0) | |||
| 202 | switch(errno(*__errno_location ())) { | |||
| 203 | /*case EAGAIN:*/ | |||
| 204 | case EWOULDBLOCK11: | |||
| 205 | n = NATPMP_TRYAGAIN(-100); | |||
| 206 | break; | |||
| 207 | case ECONNREFUSED111: | |||
| 208 | n = NATPMP_ERR_NOGATEWAYSUPPORT(-7); | |||
| 209 | break; | |||
| 210 | default: | |||
| 211 | n = NATPMP_ERR_RECVFROM(-5); | |||
| 212 | } | |||
| 213 | /* check that addr is correct (= gateway) */ | |||
| 214 | else if(addr.sin_addr.s_addr != p->gateway) | |||
| ||||
| 215 | n = NATPMP_ERR_WRONGPACKETSOURCE(-9); | |||
| 216 | else { | |||
| 217 | response->resultcode = ntohs(*((uint16_t *)(buf + 2)))(__extension__ ({ unsigned short int __v, __x = (unsigned short int) (*((uint16_t *)(buf + 2))); if (__builtin_constant_p (__x )) __v = ((unsigned short int) ((((__x) >> 8) & 0xff ) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc"); __v; })); | |||
| 218 | response->epoch = ntohl(*((uint32_t *)(buf + 4)))(__extension__ ({ unsigned int __v, __x = (*((uint32_t *)(buf + 4))); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff ) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" ( __x)); __v; })); | |||
| 219 | if(buf[0] != 0) | |||
| 220 | n = NATPMP_ERR_UNSUPPORTEDVERSION(-14); | |||
| 221 | else if(buf[1] < 128 || buf[1] > 130) | |||
| 222 | n = NATPMP_ERR_UNSUPPORTEDOPCODE(-15); | |||
| 223 | else if(response->resultcode != 0) { | |||
| 224 | switch(response->resultcode) { | |||
| 225 | case 1: | |||
| 226 | n = NATPMP_ERR_UNSUPPORTEDVERSION(-14); | |||
| 227 | break; | |||
| 228 | case 2: | |||
| 229 | n = NATPMP_ERR_NOTAUTHORIZED(-51); | |||
| 230 | break; | |||
| 231 | case 3: | |||
| 232 | n = NATPMP_ERR_NETWORKFAILURE(-52); | |||
| 233 | break; | |||
| 234 | case 4: | |||
| 235 | n = NATPMP_ERR_OUTOFRESOURCES(-53); | |||
| 236 | break; | |||
| 237 | case 5: | |||
| 238 | n = NATPMP_ERR_UNSUPPORTEDOPCODE(-15); | |||
| 239 | break; | |||
| 240 | default: | |||
| 241 | n = NATPMP_ERR_UNDEFINEDERROR(-49); | |||
| 242 | } | |||
| 243 | } else { | |||
| 244 | response->type = buf[1] & 0x7f; | |||
| 245 | if(buf[1] == 128) | |||
| 246 | //response->publicaddress.addr = *((uint32_t *)(buf + 8)); | |||
| 247 | response->pnu.publicaddress.addr.s_addr = *((uint32_t *)(buf + 8)); | |||
| 248 | else { | |||
| 249 | response->pnu.newportmapping.privateport = ntohs(*((uint16_t *)(buf + 8)))(__extension__ ({ unsigned short int __v, __x = (unsigned short int) (*((uint16_t *)(buf + 8))); if (__builtin_constant_p (__x )) __v = ((unsigned short int) ((((__x) >> 8) & 0xff ) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc"); __v; })); | |||
| 250 | response->pnu.newportmapping.mappedpublicport = ntohs(*((uint16_t *)(buf + 10)))(__extension__ ({ unsigned short int __v, __x = (unsigned short int) (*((uint16_t *)(buf + 10))); if (__builtin_constant_p ( __x)) __v = ((unsigned short int) ((((__x) >> 8) & 0xff ) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0" (__x) : "cc"); __v; })); | |||
| 251 | response->pnu.newportmapping.lifetime = ntohl(*((uint32_t *)(buf + 12)))(__extension__ ({ unsigned int __v, __x = (*((uint32_t *)(buf + 12))); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) << 8) | (((__x) & 0x000000ff ) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" ( __x)); __v; })); | |||
| 252 | } | |||
| 253 | n = 0; | |||
| 254 | } | |||
| 255 | } | |||
| 256 | return n; | |||
| 257 | } | |||
| 258 | ||||
| 259 | int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response) | |||
| 260 | { | |||
| 261 | int n; | |||
| 262 | if(!p || !response) | |||
| ||||
| 263 | return NATPMP_ERR_INVALIDARGS(-1); | |||
| 264 | if(!p->has_pending_request) | |||
| 265 | return NATPMP_ERR_NOPENDINGREQ(-6); | |||
| 266 | n = readnatpmpresponse(p, response); | |||
| 267 | if(n<0) { | |||
| 268 | if(n==NATPMP_TRYAGAIN(-100)) { | |||
| 269 | struct timeval now; | |||
| 270 | gettimeofday(&now, NULL((void*)0)); // check errors ! | |||
| 271 | if(timercmp(&now, &p->retry_time, >=)(((&now)->tv_sec == (&p->retry_time)->tv_sec ) ? ((&now)->tv_usec >= (&p->retry_time)-> tv_usec) : ((&now)->tv_sec >= (&p->retry_time )->tv_sec))) { | |||
| 272 | int delay, r; | |||
| 273 | if(p->try_number >= 9) { | |||
| 274 | return NATPMP_ERR_NOGATEWAYSUPPORT(-7); | |||
| 275 | } | |||
| 276 | /*printf("retry! %d\n", p->try_number);*/ | |||
| 277 | delay = 250 * (1<<p->try_number); // ms | |||
| 278 | /*for(i=0; i<p->try_number; i++) | |||
| 279 | delay += delay;*/ | |||
| 280 | p->retry_time.tv_sec += (delay / 1000); | |||
| 281 | p->retry_time.tv_usec += (delay % 1000) * 1000; | |||
| 282 | if(p->retry_time.tv_usec >= 1000000) { | |||
| 283 | p->retry_time.tv_usec -= 1000000; | |||
| 284 | p->retry_time.tv_sec++; | |||
| 285 | } | |||
| 286 | p->try_number++; | |||
| 287 | r = sendpendingrequest(p); | |||
| 288 | if(r<0) | |||
| 289 | return r; | |||
| 290 | } | |||
| 291 | } | |||
| 292 | } else { | |||
| 293 | p->has_pending_request = 0; | |||
| 294 | } | |||
| 295 | return n; | |||
| 296 | } | |||
| 297 | ||||
| 298 | #ifdef ENABLE_STRNATPMPERR | |||
| 299 | const char * strnatpmperr(int r) | |||
| 300 | { | |||
| 301 | const char * s; | |||
| 302 | switch(r) { | |||
| 303 | case NATPMP_ERR_INVALIDARGS(-1): | |||
| 304 | s = "invalid arguments"; | |||
| 305 | break; | |||
| 306 | case NATPMP_ERR_SOCKETERROR(-2): | |||
| 307 | s = "socket() failed"; | |||
| 308 | break; | |||
| 309 | case NATPMP_ERR_CANNOTGETGATEWAY(-3): | |||
| 310 | s = "cannot get default gateway ip address"; | |||
| 311 | break; | |||
| 312 | case NATPMP_ERR_CLOSEERR(-4): | |||
| 313 | #ifdef WIN32 | |||
| 314 | s = "closesocket() failed"; | |||
| 315 | #else | |||
| 316 | s = "close() failed"; | |||
| 317 | #endif | |||
| 318 | break; | |||
| 319 | case NATPMP_ERR_RECVFROM(-5): | |||
| 320 | s = "recvfrom() failed"; | |||
| 321 | break; | |||
| 322 | case NATPMP_ERR_NOPENDINGREQ(-6): | |||
| 323 | s = "no pending request"; | |||
| 324 | break; | |||
| 325 | case NATPMP_ERR_NOGATEWAYSUPPORT(-7): | |||
| 326 | s = "the gateway does not support nat-pmp"; | |||
| 327 | break; | |||
| 328 | case NATPMP_ERR_CONNECTERR(-8): | |||
| 329 | s = "connect() failed"; | |||
| 330 | break; | |||
| 331 | case NATPMP_ERR_WRONGPACKETSOURCE(-9): | |||
| 332 | s = "packet not received from the default gateway"; | |||
| 333 | break; | |||
| 334 | case NATPMP_ERR_SENDERR(-10): | |||
| 335 | s = "send() failed"; | |||
| 336 | break; | |||
| 337 | case NATPMP_ERR_FCNTLERROR(-11): | |||
| 338 | s = "fcntl() failed"; | |||
| 339 | break; | |||
| 340 | case NATPMP_ERR_GETTIMEOFDAYERR(-12): | |||
| 341 | s = "gettimeofday() failed"; | |||
| 342 | break; | |||
| 343 | case NATPMP_ERR_UNSUPPORTEDVERSION(-14): | |||
| 344 | s = "unsupported nat-pmp version error from server"; | |||
| 345 | break; | |||
| 346 | case NATPMP_ERR_UNSUPPORTEDOPCODE(-15): | |||
| 347 | s = "unsupported nat-pmp opcode error from server"; | |||
| 348 | break; | |||
| 349 | case NATPMP_ERR_UNDEFINEDERROR(-49): | |||
| 350 | s = "undefined nat-pmp server error"; | |||
| 351 | break; | |||
| 352 | case NATPMP_ERR_NOTAUTHORIZED(-51): | |||
| 353 | s = "not authorized"; | |||
| 354 | break; | |||
| 355 | case NATPMP_ERR_NETWORKFAILURE(-52): | |||
| 356 | s = "network failure"; | |||
| 357 | break; | |||
| 358 | case NATPMP_ERR_OUTOFRESOURCES(-53): | |||
| 359 | s = "nat-pmp server out of resources"; | |||
| 360 | break; | |||
| 361 | default: | |||
| 362 | s = "Unknown libnatpmp error"; | |||
| 363 | } | |||
| 364 | return s; | |||
| 365 | } | |||
| 366 | #endif | |||
| 367 |