265 ? (((struct sockaddr_in*)sa)->sin_port) |
267 ? (((struct sockaddr_in*)sa)->sin_port) |
266 : (((struct sockaddr_in6*)sa)->sin6_port)); |
268 : (((struct sockaddr_in6*)sa)->sin6_port)); |
267 } |
269 } |
268 |
270 |
269 /* |
271 /* |
|
272 * Parses scope id. |
|
273 * Scope id is ulong on Windows, uint32 on unix, so returns long which can be cast to uint32. |
|
274 * On error sets last error and returns -1. |
|
275 */ |
|
276 static long parseScopeId(const char *str) { |
|
277 // try to handle scope as interface name |
|
278 unsigned long scopeId = if_nametoindex(str); |
|
279 if (scopeId == 0) { |
|
280 // try to parse integer value |
|
281 char *end; |
|
282 scopeId = strtoul(str, &end, 10); |
|
283 if (*end != '\0') { |
|
284 setLastError(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "failed to parse scope"); |
|
285 return -1; |
|
286 } |
|
287 } |
|
288 // ensure parsed value is in uint32 range |
|
289 if (scopeId > 0xFFFFFFFF) { |
|
290 setLastError(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "scope is out of range"); |
|
291 return -1; |
|
292 } |
|
293 return (long)scopeId; |
|
294 } |
|
295 |
|
296 /* |
|
297 * Wrapper for dbgsysGetAddrInfo (getaddrinfo). |
|
298 * Handles enclosing square brackets and scopes. |
|
299 */ |
|
300 static jdwpTransportError |
|
301 getAddrInfo(const char *hostname, size_t hostnameLen, |
|
302 const char *service, |
|
303 const struct addrinfo *hints, |
|
304 struct addrinfo **result) |
|
305 { |
|
306 int err = 0; |
|
307 char *buffer = NULL; |
|
308 long scopeId = 0; |
|
309 |
|
310 if (hostname != NULL) { |
|
311 char *scope = NULL; |
|
312 // skip surrounding |
|
313 if (hostnameLen > 2 && hostname[0] == '[' && hostname[hostnameLen - 1] == ']') { |
|
314 hostname++; |
|
315 hostnameLen -= 2; |
|
316 } |
|
317 buffer = (*callback->alloc)((int)hostnameLen + 1); |
|
318 if (buffer == NULL) { |
|
319 RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory"); |
|
320 } |
|
321 memcpy(buffer, hostname, hostnameLen); |
|
322 buffer[hostnameLen] = '\0'; |
|
323 |
|
324 scope = strchr(buffer, '%'); |
|
325 if (scope != NULL) { |
|
326 // drop scope from the address |
|
327 *scope = '\0'; |
|
328 // and parse the value |
|
329 scopeId = parseScopeId(scope + 1); |
|
330 if (scopeId < 0) { |
|
331 (*callback->free)(buffer); |
|
332 return JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT; |
|
333 } |
|
334 } |
|
335 } |
|
336 |
|
337 err = dbgsysGetAddrInfo(buffer, service, hints, result); |
|
338 |
|
339 if (buffer != NULL) { |
|
340 (*callback->free)(buffer); |
|
341 } |
|
342 if (err != 0) { |
|
343 setLastError(err, "getaddrinfo: failed to parse address"); |
|
344 return JDWPTRANSPORT_ERROR_IO_ERROR; |
|
345 } |
|
346 |
|
347 if (scopeId > 0) { |
|
348 if ((*result)->ai_family != AF_INET6) { |
|
349 RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "IPv4 address cannot contain scope"); |
|
350 } |
|
351 |
|
352 ((struct sockaddr_in6 *)((*result)->ai_addr))->sin6_scope_id = (uint32_t)scopeId; |
|
353 } |
|
354 |
|
355 return JDWPTRANSPORT_ERROR_NONE; |
|
356 } |
|
357 |
|
358 /* |
270 * Result must be released with dbgsysFreeAddrInfo. |
359 * Result must be released with dbgsysFreeAddrInfo. |
271 */ |
360 */ |
272 static jdwpTransportError |
361 static jdwpTransportError |
273 parseAddress(const char *address, struct addrinfo **result) { |
362 parseAddress(const char *address, struct addrinfo **result) { |
274 const char *colon; |
363 const char *colon; |
275 size_t hostLen; |
364 size_t hostnameLen; |
276 char *host = NULL; |
|
277 const char *port; |
365 const char *port; |
278 struct addrinfo hints; |
366 struct addrinfo hints; |
279 int res; |
|
280 |
367 |
281 *result = NULL; |
368 *result = NULL; |
282 |
369 |
283 /* check for host:port or port */ |
370 /* check for host:port or port */ |
284 colon = strrchr(address, ':'); |
371 colon = strrchr(address, ':'); |
293 hints.ai_family = allowOnlyIPv4 ? AF_INET : AF_UNSPEC; |
380 hints.ai_family = allowOnlyIPv4 ? AF_INET : AF_UNSPEC; |
294 hints.ai_socktype = SOCK_STREAM; |
381 hints.ai_socktype = SOCK_STREAM; |
295 hints.ai_protocol = IPPROTO_TCP; |
382 hints.ai_protocol = IPPROTO_TCP; |
296 hints.ai_flags = AI_NUMERICSERV; // port must be a number |
383 hints.ai_flags = AI_NUMERICSERV; // port must be a number |
297 |
384 |
298 hostLen = (colon == NULL ? 0 : colon - address); |
385 hostnameLen = (colon == NULL ? 0 : colon - address); |
299 if (hostLen == 0) { |
386 if (hostnameLen == 0) { |
300 /* no hostname - use localhost address (pass NULL to getaddrinfo) */ |
387 /* no hostname - use localhost address (pass NULL to getaddrinfo) */ |
301 } else if (*address == '*' && hostLen == 1) { |
388 address = NULL; |
|
389 } else if (*address == '*' && hostnameLen == 1) { |
302 /* *:port - listen on all interfaces |
390 /* *:port - listen on all interfaces |
303 * use IPv6 socket (to accept IPv6 and mapped IPv4), |
391 * use IPv6 socket (to accept IPv6 and mapped IPv4), |
304 * pass hostname == NULL to getaddrinfo. |
392 * pass hostname == NULL to getaddrinfo. |
305 */ |
393 */ |
306 hints.ai_family = allowOnlyIPv4 ? AF_INET : AF_INET6; |
394 hints.ai_family = allowOnlyIPv4 ? AF_INET : AF_INET6; |
307 hints.ai_flags |= AI_PASSIVE | (allowOnlyIPv4 ? 0 : AI_V4MAPPED | AI_ALL); |
395 hints.ai_flags |= AI_PASSIVE | (allowOnlyIPv4 ? 0 : AI_V4MAPPED | AI_ALL); |
308 } else { |
396 address = NULL; |
309 if (address[0] == '[' && colon[-1] == ']') { |
397 } |
310 address++; |
398 |
311 hostLen -= 2; |
399 return getAddrInfo(address, hostnameLen, port, &hints, result); |
312 } |
|
313 host = (*callback->alloc)((int)hostLen + 1); |
|
314 if (host == NULL) { |
|
315 RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory"); |
|
316 } |
|
317 strncpy(host, address, hostLen); |
|
318 host[hostLen] = '\0'; |
|
319 } |
|
320 |
|
321 res = dbgsysGetAddrInfo(host, port, &hints, result); |
|
322 if (host != NULL) { |
|
323 (*callback->free)(host); |
|
324 } |
|
325 if (res != 0) { |
|
326 setLastError(res, "getaddrinfo: unknown host"); |
|
327 return JDWPTRANSPORT_ERROR_IO_ERROR; |
|
328 } |
|
329 |
|
330 return JDWPTRANSPORT_ERROR_NONE; |
|
331 } |
400 } |
332 |
401 |
333 /* |
402 /* |
334 * Input is sockaddr just because all clients have it. |
403 * Input is sockaddr just because all clients have it. |
335 */ |
404 */ |
350 */ |
419 */ |
351 static jdwpTransportError |
420 static jdwpTransportError |
352 parseAllowedAddr(const char *buffer, struct in6_addr *result, int *isIPv4) { |
421 parseAllowedAddr(const char *buffer, struct in6_addr *result, int *isIPv4) { |
353 struct addrinfo hints; |
422 struct addrinfo hints; |
354 struct addrinfo *addrInfo = NULL; |
423 struct addrinfo *addrInfo = NULL; |
355 int err; |
424 jdwpTransportError err; |
356 |
425 |
357 /* |
426 /* |
358 * To parse both IPv4 and IPv6 need to specify AF_UNSPEC family |
427 * To parse both IPv4 and IPv6 need to specify AF_UNSPEC family |
359 * (with AF_INET6 IPv4 addresses are not parsed even with AI_V4MAPPED and AI_ALL flags). |
428 * (with AF_INET6 IPv4 addresses are not parsed even with AI_V4MAPPED and AI_ALL flags). |
360 */ |
429 */ |
362 hints.ai_family = AF_UNSPEC; // IPv6 or mapped IPv4 |
431 hints.ai_family = AF_UNSPEC; // IPv6 or mapped IPv4 |
363 hints.ai_socktype = SOCK_STREAM; |
432 hints.ai_socktype = SOCK_STREAM; |
364 hints.ai_protocol = IPPROTO_TCP; |
433 hints.ai_protocol = IPPROTO_TCP; |
365 hints.ai_flags = AI_NUMERICHOST; // only numeric addresses, no resolution |
434 hints.ai_flags = AI_NUMERICHOST; // only numeric addresses, no resolution |
366 |
435 |
367 err = dbgsysGetAddrInfo(buffer, NULL, &hints, &addrInfo); |
436 err = getAddrInfo(buffer, strlen(buffer), NULL, &hints, &addrInfo); |
368 |
437 |
369 if (err != 0) { |
438 if (err != JDWPTRANSPORT_ERROR_NONE) { |
370 setLastError(err, "getaddrinfo: failed to parse address"); |
439 return err; |
371 return JDWPTRANSPORT_ERROR_IO_ERROR; |
|
372 } |
440 } |
373 |
441 |
374 if (addrInfo->ai_family == AF_INET6) { |
442 if (addrInfo->ai_family == AF_INET6) { |
375 memcpy(result, &(((struct sockaddr_in6 *)(addrInfo->ai_addr))->sin6_addr), sizeof(*result)); |
443 memcpy(result, &(((struct sockaddr_in6 *)(addrInfo->ai_addr))->sin6_addr), sizeof(*result)); |
376 *isIPv4 = 0; |
444 *isIPv4 = 0; |
842 if (timeout > 0) { |
910 if (timeout > 0) { |
843 dbgsysConfigureBlocking(socketFD, JNI_FALSE); |
911 dbgsysConfigureBlocking(socketFD, JNI_FALSE); |
844 } |
912 } |
845 |
913 |
846 err = dbgsysConnect(socketFD, ai->ai_addr, (socklen_t)ai->ai_addrlen); |
914 err = dbgsysConnect(socketFD, ai->ai_addr, (socklen_t)ai->ai_addrlen); |
|
915 |
847 if (err == DBG_EINPROGRESS && timeout > 0) { |
916 if (err == DBG_EINPROGRESS && timeout > 0) { |
848 err = dbgsysFinishConnect(socketFD, (long)timeout); |
917 err = dbgsysFinishConnect(socketFD, (long)timeout); |
849 |
918 |
850 if (err == DBG_ETIMEOUT) { |
919 if (err == DBG_ETIMEOUT) { |
851 dbgsysConfigureBlocking(socketFD, JNI_TRUE); |
920 dbgsysConfigureBlocking(socketFD, JNI_TRUE); |