Changeset 1601 for pjproject/trunk/pjlib/src/pj/sock_common.c
- Timestamp:
- Dec 1, 2007 8:52:57 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjlib/src/pj/sock_common.c
r1585 r1601 18 18 */ 19 19 #include <pj/sock.h> 20 #include <pj/assert.h> 21 #include <pj/errno.h> 22 #include <pj/ip_helper.h> 23 #include <pj/os.h> 24 #include <pj/addr_resolv.h> 25 #include <pj/string.h> 26 #include <pj/compat/socket.h> 27 28 29 /* 30 * Convert address string with numbers and dots to binary IP address. 31 */ 32 PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) 33 { 34 pj_in_addr addr; 35 36 pj_inet_aton(cp, &addr); 37 return addr; 38 } 39 40 /* 41 * Convert address string with numbers and dots to binary IP address. 42 */ 43 PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp) 44 { 45 pj_str_t str = pj_str((char*)cp); 46 return pj_inet_addr(&str); 47 } 48 49 /* 50 * Set the IP address of an IP socket address from string address, 51 * with resolving the host if necessary. The string address may be in a 52 * standard numbers and dots notation or may be a hostname. If hostname 53 * is specified, then the function will resolve the host into the IP 54 * address. 55 */ 56 PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, 57 const pj_str_t *str_addr) 58 { 59 PJ_CHECK_STACK(); 60 61 PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME, 62 (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); 63 64 PJ_SOCKADDR_RESET_LEN(addr); 65 addr->sin_family = AF_INET; 66 pj_bzero(addr->sin_zero, sizeof(addr->sin_zero)); 67 68 if (str_addr && str_addr->slen) { 69 addr->sin_addr = pj_inet_addr(str_addr); 70 if (addr->sin_addr.s_addr == PJ_INADDR_NONE) { 71 pj_hostent he; 72 pj_status_t rc; 73 74 rc = pj_gethostbyname(str_addr, &he); 75 if (rc == 0) { 76 addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; 77 } else { 78 addr->sin_addr.s_addr = PJ_INADDR_NONE; 79 return rc; 80 } 81 } 82 83 } else { 84 addr->sin_addr.s_addr = 0; 85 } 86 87 return PJ_SUCCESS; 88 } 89 90 /* Set address from a name */ 91 PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af, 92 pj_sockaddr *addr, 93 const pj_str_t *str_addr) 94 { 95 pj_status_t status; 96 97 if (af == PJ_AF_INET) { 98 return pj_sockaddr_in_set_str_addr(&addr->ipv4, str_addr); 99 } 100 101 PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP); 102 103 /* IPv6 specific */ 104 105 addr->ipv6.sin6_family = PJ_AF_INET6; 106 PJ_SOCKADDR_RESET_LEN(addr); 107 108 if (str_addr && str_addr->slen) { 109 status = pj_inet_pton(PJ_AF_INET6, str_addr, &addr->ipv6.sin6_addr); 110 if (status != PJ_SUCCESS) { 111 pj_addrinfo ai; 112 unsigned count = 1; 113 114 status = pj_getaddrinfo(PJ_AF_INET6, str_addr, &count, &ai); 115 if (status==PJ_SUCCESS) { 116 pj_memcpy(&addr->ipv6.sin6_addr, &ai.ai_addr.ipv6.sin6_addr, 117 sizeof(pj_sockaddr_in6)); 118 } 119 } 120 } else { 121 status = PJ_SUCCESS; 122 } 123 124 return status; 125 } 126 127 /* 128 * Set the IP address and port of an IP socket address. 129 * The string address may be in a standard numbers and dots notation or 130 * may be a hostname. If hostname is specified, then the function will 131 * resolve the host into the IP address. 132 */ 133 PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, 134 const pj_str_t *str_addr, 135 pj_uint16_t port) 136 { 137 PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); 138 139 PJ_SOCKADDR_RESET_LEN(addr); 140 addr->sin_family = PJ_AF_INET; 141 pj_bzero(addr->sin_zero, sizeof(addr->sin_zero)); 142 pj_sockaddr_in_set_port(addr, port); 143 return pj_sockaddr_in_set_str_addr(addr, str_addr); 144 } 145 146 /* 147 * Initialize IP socket address based on the address and port info. 148 */ 149 PJ_DEF(pj_status_t) pj_sockaddr_init(int af, 150 pj_sockaddr *addr, 151 const pj_str_t *cp, 152 pj_uint16_t port) 153 { 154 pj_status_t status; 155 156 if (af == PJ_AF_INET) { 157 return pj_sockaddr_in_init(&addr->ipv4, cp, port); 158 } 159 160 /* IPv6 specific */ 161 PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP); 162 163 pj_bzero(addr, sizeof(pj_sockaddr_in6)); 164 addr->addr.sa_family = PJ_AF_INET6; 165 166 status = pj_sockaddr_set_str_addr(af, addr, cp); 167 if (status != PJ_SUCCESS) 168 return status; 169 170 addr->ipv6.sin6_port = pj_htons(port); 171 return PJ_SUCCESS; 172 } 173 174 /* 175 * Get first IP address associated with the hostname. 176 */ 177 PJ_DEF(pj_in_addr) pj_gethostaddr(void) 178 { 179 pj_sockaddr_in addr; 180 const pj_str_t *hostname = pj_gethostname(); 181 182 pj_sockaddr_in_set_str_addr(&addr, hostname); 183 return addr.sin_addr; 184 } 185 186 /* 187 * Get port number of a pj_sockaddr_in 188 */ 189 PJ_DEF(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr) 190 { 191 return pj_ntohs(addr->sin_port); 192 } 193 194 /* 195 * Get the address part 196 */ 197 PJ_DEF(void*) pj_sockaddr_get_addr(const pj_sockaddr_t *addr) 198 { 199 const pj_sockaddr *a = (const pj_sockaddr*)addr; 200 201 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || 202 a->addr.sa_family == PJ_AF_INET6, NULL); 203 204 if (a->addr.sa_family == PJ_AF_INET6) 205 return (void*) &a->ipv6.sin6_addr; 206 else 207 return (void*) &a->ipv4.sin_addr; 208 } 209 210 /* 211 * Check if sockaddr contains a non-zero address 212 */ 213 PJ_DEF(pj_bool_t) pj_sockaddr_has_addr(const pj_sockaddr_t *addr) 214 { 215 const pj_sockaddr *a = (const pj_sockaddr*)addr; 216 217 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || 218 a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP); 219 220 if (a->addr.sa_family == PJ_AF_INET6) { 221 pj_uint8_t zero[24]; 222 pj_bzero(zero, sizeof(zero)); 223 return pj_memcmp(a->ipv6.sin6_addr.s6_addr, zero, 224 sizeof(pj_in6_addr)) != 0; 225 } else 226 return a->ipv4.sin_addr.s_addr != PJ_INADDR_ANY; 227 } 228 229 /* 230 * Get port number 231 */ 232 PJ_DEF(pj_uint16_t) pj_sockaddr_get_port(const pj_sockaddr_t *addr) 233 { 234 const pj_sockaddr *a = (const pj_sockaddr*) addr; 235 236 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || 237 a->addr.sa_family == PJ_AF_INET6, (pj_uint16_t)0xFFFF); 238 239 return pj_ntohs((pj_uint16_t)(a->addr.sa_family == PJ_AF_INET6 ? 240 a->ipv6.sin6_port : a->ipv4.sin_port)); 241 } 242 243 /* 244 * Get the length of the address part. 245 */ 246 PJ_DEF(unsigned) pj_sockaddr_get_addr_len(const pj_sockaddr_t *addr) 247 { 248 const pj_sockaddr *a = (const pj_sockaddr*) addr; 249 PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || 250 a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP); 251 return a->addr.sa_family == PJ_AF_INET6 ? 252 sizeof(pj_in6_addr) : sizeof(pj_in_addr); 253 } 254 255 /* 256 * Set port number of pj_sockaddr_in 257 */ 258 PJ_DEF(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, 259 pj_uint16_t hostport) 260 { 261 addr->sin_port = pj_htons(hostport); 262 } 263 264 /* 265 * Set port number of pj_sockaddr 266 */ 267 PJ_DEF(pj_status_t) pj_sockaddr_set_port(pj_sockaddr *addr, 268 pj_uint16_t hostport) 269 { 270 int af = addr->addr.sa_family; 271 272 PJ_ASSERT_ON_FAIL(af == PJ_AF_INET || af == PJ_AF_INET6, 273 PJ_EINVAL); 274 275 if (af == PJ_AF_INET6) 276 addr->ipv6.sin6_port = pj_htons(hostport); 277 else 278 addr->ipv4.sin_port = pj_htons(hostport); 279 280 return PJ_SUCCESS; 281 } 282 283 /* 284 * Get IPv4 address 285 */ 286 PJ_DEF(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr) 287 { 288 pj_in_addr in_addr; 289 in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr); 290 return in_addr; 291 } 292 293 /* 294 * Set IPv4 address 295 */ 296 PJ_DEF(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr, 297 pj_uint32_t hostaddr) 298 { 299 addr->sin_addr.s_addr = pj_htonl(hostaddr); 300 } 301 302 /* Resolve the IP address of local machine */ 303 PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr) 304 { 305 unsigned count; 306 pj_addrinfo ai; 307 pj_status_t status; 308 309 310 #ifdef _MSC_VER 311 /* Get rid of "uninitialized he variable" with MS compilers */ 312 pj_bzero(&ai, sizeof(ai)); 313 #endif 314 315 addr->addr.sa_family = (pj_uint16_t)af; 316 PJ_SOCKADDR_RESET_LEN(addr); 317 318 /* Try with resolving local hostname first */ 319 count = 1; 320 status = pj_getaddrinfo(af, pj_gethostname(), &count, &ai); 321 if (status == PJ_SUCCESS) { 322 pj_memcpy(pj_sockaddr_get_addr(addr), 323 pj_sockaddr_get_addr(&ai.ai_addr), 324 pj_sockaddr_get_addr_len(&ai.ai_addr)); 325 } 326 327 328 /* If we end up with 127.x.x.x, resolve the IP by getting the default 329 * interface to connect to some public host. 330 */ 331 if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(addr) || 332 (af==PJ_AF_INET && (pj_ntohl(addr->ipv4.sin_addr.s_addr) >> 24)==127)) 333 { 334 status = pj_getdefaultipinterface(af, addr); 335 } 336 337 /* If failed, get the first available interface */ 338 if (status != PJ_SUCCESS) { 339 pj_sockaddr itf[1]; 340 unsigned count = PJ_ARRAY_SIZE(itf); 341 342 status = pj_enum_ip_interface(af, &count, itf); 343 if (status == PJ_SUCCESS) { 344 itf[0].addr.sa_family = (pj_uint16_t)af; 345 pj_memcpy(pj_sockaddr_get_addr(addr), 346 pj_sockaddr_get_addr(&itf[0]), 347 pj_sockaddr_get_addr_len(&itf[0])); 348 } 349 } 350 351 /* If else fails, returns loopback interface as the last resort */ 352 if (status != PJ_SUCCESS) { 353 if (af==PJ_AF_INET) { 354 addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001); 355 } else { 356 pj_in6_addr *s6_addr; 357 358 s6_addr = (pj_in6_addr*) pj_sockaddr_get_addr(addr); 359 pj_bzero(s6_addr, sizeof(pj_in6_addr)); 360 s6_addr->s6_addr[15] = 1; 361 } 362 status = PJ_SUCCESS; 363 } 364 365 return status; 366 } 367 368 /* Get the default IP interface */ 369 PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr) 370 { 371 pj_sock_t fd; 372 pj_str_t cp; 373 pj_sockaddr a; 374 int len; 375 pj_uint8_t zero[64]; 376 pj_status_t status; 377 378 addr->addr.sa_family = (pj_uint16_t)af; 379 380 status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd); 381 if (status != PJ_SUCCESS) { 382 return status; 383 } 384 385 if (af == PJ_AF_INET) { 386 cp = pj_str("1.1.1.1"); 387 } else { 388 cp = pj_str("1::1"); 389 } 390 status = pj_sockaddr_init(af, &a, &cp, 53); 391 if (status != PJ_SUCCESS) { 392 pj_sock_close(fd); 393 return status; 394 } 395 396 status = pj_sock_connect(fd, &a, sizeof(a)); 397 if (status != PJ_SUCCESS) { 398 pj_sock_close(fd); 399 return status; 400 } 401 402 len = sizeof(a); 403 status = pj_sock_getsockname(fd, &a, &len); 404 if (status != PJ_SUCCESS) { 405 pj_sock_close(fd); 406 return status; 407 } 408 409 pj_sock_close(fd); 410 411 /* Check that the address returned is not zero */ 412 pj_bzero(zero, sizeof(zero)); 413 if (pj_memcmp(pj_sockaddr_get_addr(&a), zero, 414 pj_sockaddr_get_addr_len(&a))==0) 415 { 416 return PJ_ENOTFOUND; 417 } 418 419 pj_memcpy(pj_sockaddr_get_addr(addr), 420 pj_sockaddr_get_addr(&a), 421 pj_sockaddr_get_addr_len(&a)); 422 423 /* Success */ 424 return PJ_SUCCESS; 425 } 426 427 428 /* Only need to implement these in DLL build */ 429 #if defined(PJ_DLL) 20 430 21 431 PJ_DEF(pj_uint16_t) pj_AF_UNSPEC(void) … … 149 559 } 150 560 561 #endif /* PJ_DLL */ 562
Note: See TracChangeset
for help on using the changeset viewer.