1 /*
2  * Socket6.xs
3  * $Id: Socket6.xs 688 2018-09-30 04:22:53Z ume $
4  *
5  * Copyright (C) 2000-2018 Hajimu UMEMOTO <ume@mahoroba.org>.
6  * All rights reserved.
7  *
8  * This moduled is besed on perl5.005_55-v6-19990721 written by KAME
9  * Project.
10  *
11  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. Neither the name of the project nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #ifdef WIN32
40 
41 #define	WINVER		0x0501
42 #include <winsock2.h>
43 #include <ws2tcpip.h>
44 #ifndef NI_NUMERICSERV
45 #error Microsoft Platform SDK (Aug. 2001) or later required.
46 #endif
47 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
48 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
49 #define	WSA_DECLARE					\
50 	WSADATA wsaData;				\
51 	int wsa = 0
52 #define	WSA_STARTUP()					\
53 	wsa = WSAStartup(MAKEWORD(2,2), &wsaData)
54 #define	WSA_CLEANUP()					\
55 	if (!wsa) WSACleanup()
56 
57 #else /* WIN32 */
58 
59 #include <sys/types.h>
60 #include <sys/socket.h>
61 #include <netinet/in.h>
62 #ifdef __KAME__
63 # include <sys/param.h>
64 # include <net/route.h>
65 # if (defined(__FreeBSD__) && __FreeBSD_version >= 700048) || \
66      (defined(__NetBSD__) && __NetBSD_Version__ >= 899002500)
67 #  include <netipsec/ipsec.h>
68 # elif !defined(__OpenBSD__) && !defined(__DragonFly__)
69 #  include <netinet6/ipsec.h>
70 # endif
71 #endif
72 #include <netdb.h>
73 #define	WSA_DECLARE
74 #define	WSA_STARTUP()
75 #define	WSA_CLEANUP()
76 
77 #endif /* WIN32 */
78 
79 #include "EXTERN.h"
80 #include "perl.h"
81 #include "XSUB.h"
82 
83 #include "config.h"
84 
85 #if defined(HAVE_INET_NTOP) && !defined(CAN_INET_NTOP)
86 #undef HAVE_INET_NTOP
87 #endif
88 
89 #ifndef HAVE_GETADDRINFO
90 #include "getaddrinfo.c"
91 #define	NI_MAXHOST		1025
92 #define	NI_MAXSERV		32
93 #define	HAVE_GETADDRINFO	1
94 #endif
95 #ifndef	HAVE_GETNAMEINFO
96 #include "getnameinfo.c"
97 #define	HAVE_GETNAMEINFO	1
98 #endif
99 
100 #ifndef HAVE_INET_NTOP
101 #include "inet_ntop.c"
102 #define	HAVE_INET_NTOP		1
103 #endif
104 #ifndef HAVE_INET_PTON
105 #include "inet_pton.c"
106 #define	HAVE_INET_PTON		1
107 #endif
108 
109 #ifndef HAVE_PL_SV_UNDEF
110 #define	PL_sv_undef		sv_undef
111 #endif
112 
113 static int
not_here(char * s)114 not_here(char *s)
115 {
116     croak("Socket6::%s not implemented on this architecture", s);
117     return -1;
118 }
119 
120 static double
constant(char * name,int arg)121 constant(char *name, int arg)
122 {
123     errno = 0;
124     switch (*name) {
125     case 'A':
126 	if (strEQ(name, "AF_INET6"))
127 #ifdef AF_INET6
128 	    return AF_INET6;
129 #else
130 	    goto not_there;
131 #endif
132 	if (strEQ(name, "AI_ADDRCONFIG"))
133 #ifdef AI_ADDRCONFIG
134 	    return AI_ADDRCONFIG;
135 #else
136 	    goto not_there;
137 #endif
138 	if (strEQ(name, "AI_ALL"))
139 #ifdef AI_ALL
140 	    return AI_ALL;
141 #else
142 	    goto not_there;
143 #endif
144 	if (strEQ(name, "AI_CANONNAME"))
145 #ifdef AI_CANONNAME
146 	    return AI_CANONNAME;
147 #else
148 	    goto not_there;
149 #endif
150 	if (strEQ(name, "AI_NUMERICHOST"))
151 #ifdef AI_NUMERICHOST
152 	    return AI_NUMERICHOST;
153 #else
154 	    goto not_there;
155 #endif
156 	if (strEQ(name, "AI_NUMERICSERV"))
157 #ifdef AI_NUMERICSERV
158 	    return AI_NUMERICSERV;
159 #else
160 	    goto not_there;
161 #endif
162 	if (strEQ(name, "AI_DEFAULT"))
163 #ifdef AI_DEFAULT
164 	    return AI_DEFAULT;
165 #else
166 	    goto not_there;
167 #endif
168 	if (strEQ(name, "AI_MASK"))
169 #ifdef AI_MASK
170 	    return AI_MASK;
171 #else
172 	    goto not_there;
173 #endif
174 	if (strEQ(name, "AI_PASSIVE"))
175 #ifdef AI_PASSIVE
176 	    return AI_PASSIVE;
177 #else
178 	    goto not_there;
179 #endif
180 	if (strEQ(name, "AI_V4MAPPED"))
181 #ifdef AI_V4MAPPED
182 	    return AI_V4MAPPED;
183 #else
184 	    goto not_there;
185 #endif
186 	if (strEQ(name, "AI_V4MAPPED_CFG"))
187 #ifdef AI_V4MAPPED_CFG
188 	    return AI_V4MAPPED_CFG;
189 #else
190 	    goto not_there;
191 #endif
192 	break;
193     case 'E':
194 	if (strEQ(name, "EAI_ADDRFAMILY"))
195 #ifdef EAI_ADDRFAMILY
196 	    return EAI_ADDRFAMILY;
197 #else
198 	    goto not_there;
199 #endif
200 	if (strEQ(name, "EAI_AGAIN"))
201 #ifdef EAI_AGAIN
202 	    return EAI_AGAIN;
203 #else
204 	    goto not_there;
205 #endif
206 	if (strEQ(name, "EAI_BADFLAGS"))
207 #ifdef EAI_BADFLAGS
208 	    return EAI_BADFLAGS;
209 #else
210 	    goto not_there;
211 #endif
212 	if (strEQ(name, "EAI_FAIL"))
213 #ifdef EAI_FAIL
214 	    return EAI_FAIL;
215 #else
216 	    goto not_there;
217 #endif
218 	if (strEQ(name, "EAI_FAMILY"))
219 #ifdef EAI_FAMILY
220 	    return EAI_FAMILY;
221 #else
222 	    goto not_there;
223 #endif
224 	if (strEQ(name, "EAI_MEMORY"))
225 #ifdef EAI_MEMORY
226 	    return EAI_MEMORY;
227 #else
228 	    goto not_there;
229 #endif
230 	if (strEQ(name, "EAI_NODATA"))
231 #ifdef EAI_NODATA
232 	    return EAI_NODATA;
233 #else
234 	    goto not_there;
235 #endif
236 	if (strEQ(name, "EAI_NONAME"))
237 #ifdef EAI_NONAME
238 	    return EAI_NONAME;
239 #else
240 	    goto not_there;
241 #endif
242 	if (strEQ(name, "EAI_SERVICE"))
243 #ifdef EAI_SERVICE
244 	    return EAI_SERVICE;
245 #else
246 	    goto not_there;
247 #endif
248 	if (strEQ(name, "EAI_SOCKTYPE"))
249 #ifdef EAI_SOCKTYPE
250 	    return EAI_SOCKTYPE;
251 #else
252 	    goto not_there;
253 #endif
254 	if (strEQ(name, "EAI_SYSTEM"))
255 #ifdef EAI_SYSTEM
256 	    return EAI_SYSTEM;
257 #else
258 	    goto not_there;
259 #endif
260 	if (strEQ(name, "EAI_BADHINTS"))
261 #ifdef EAI_BADHINTS
262 	    return EAI_BADHINTS;
263 #else
264 	    goto not_there;
265 #endif
266 	if (strEQ(name, "EAI_PROTOCOL"))
267 #ifdef EAI_PROTOCOL
268 	    return EAI_PROTOCOL;
269 #else
270 	    goto not_there;
271 #endif
272 	break;
273     case 'I':
274 	if (strEQ(name, "IP_AUTH_TRANS_LEVEL"))
275 #ifdef IP_AUTH_TRANS_LEVEL
276 	    return IP_AUTH_TRANS_LEVEL;
277 #else
278 	    goto not_there;
279 #endif
280 	if (strEQ(name, "IP_AUTH_NETWORK_LEVEL"))
281 #ifdef IP_AUTH_NETWORK_LEVEL
282 	    return IP_AUTH_NETWORK_LEVEL;
283 #else
284 	    goto not_there;
285 #endif
286 	if (strEQ(name, "IP_ESP_TRANS_LEVEL"))
287 #ifdef IP_ESP_TRANS_LEVEL
288 	    return IP_ESP_TRANS_LEVEL;
289 #else
290 	    goto not_there;
291 #endif
292 	if (strEQ(name, "IP_EPS_NETWORK_LEVEL"))
293 #ifdef IP_EPS_NETWORK_LEVEL
294 	    return IP_EPS_NETWORK_LEVEL;
295 #else
296 	    goto not_there;
297 #endif
298 	if (strEQ(name, "IPPROTO_IP"))
299 #ifdef IPPROTO_IP
300 	    return IPPROTO_IP;
301 #else
302 	    goto not_there;
303 #endif
304 	if (strEQ(name, "IPPROTO_IPV6"))
305 #ifdef IPPROTO_IPV6
306 	    return IPPROTO_IPV6;
307 #else
308 	    goto not_there;
309 #endif
310 	if (strEQ(name, "IPSEC_LEVEL_AVAIL"))
311 #ifdef IPSEC_LEVEL_AVAIL
312 	    return IPSEC_LEVEL_AVAIL;
313 #else
314 	    goto not_there;
315 #endif
316 	if (strEQ(name, "IPSEC_LEVEL_BYPASS"))
317 #ifdef IPSEC_LEVEL_BYPASS
318 	    return IPSEC_LEVEL_BYPASS;
319 #else
320 	    goto not_there;
321 #endif
322 	if (strEQ(name, "IPSEC_LEVEL_DEFAULT"))
323 #ifdef IPSEC_LEVEL_DEFAULT
324 	    return IPSEC_LEVEL_DEFAULT;
325 #else
326 	    goto not_there;
327 #endif
328 	if (strEQ(name, "IPSEC_LEVEL_NONE"))
329 #ifdef IPSEC_LEVEL_NONE
330 	    return IPSEC_LEVEL_NONE;
331 #else
332 	    goto not_there;
333 #endif
334 	if (strEQ(name, "IPSEC_LEVEL_REQUIRE"))
335 #ifdef IPSEC_LEVEL_REQUIRE
336 	    return IPSEC_LEVEL_REQUIRE;
337 #else
338 	    goto not_there;
339 #endif
340 	if (strEQ(name, "IPSEC_LEVEL_UNIQUE"))
341 #ifdef IPSEC_LEVEL_UNIQUE
342 	    return IPSEC_LEVEL_UNIQUE;
343 #else
344 	    goto not_there;
345 #endif
346 	if (strEQ(name, "IPSEC_LEVEL_USE"))
347 #ifdef IPSEC_LEVEL_USE
348 	    return IPSEC_LEVEL_USE;
349 #else
350 	    goto not_there;
351 #endif
352 	if (strEQ(name, "IPV6_AUTH_TRANS_LEVEL"))
353 #ifdef IPV6_AUTH_TRANS_LEVEL
354 	    return IPV6_AUTH_TRANS_LEVEL;
355 #else
356 	    goto not_there;
357 #endif
358 	if (strEQ(name, "IPV6_AUTH_NETWORK_LEVEL"))
359 #ifdef IPV6_AUTH_NETWORK_LEVEL
360 	    return IPV6_AUTH_NETWORK_LEVEL;
361 #else
362 	    goto not_there;
363 #endif
364 	if (strEQ(name, "IPV6_ESP_TRANS_LEVEL"))
365 #ifdef IPV6_ESP_TRANS_LEVEL
366 	    return IPV6_ESP_TRANS_LEVEL;
367 #else
368 	    goto not_there;
369 #endif
370 	if (strEQ(name, "IPV6_EPS_NETWORK_LEVEL"))
371 #ifdef IPV6_EPS_NETWORK_LEVEL
372 	    return IPV6_EPS_NETWORK_LEVEL;
373 #else
374 	    goto not_there;
375 #endif
376 	break;
377     case 'N':
378 	if (strEQ(name, "NI_NOFQDN"))
379 #ifdef NI_NOFQDN
380 	    return NI_NOFQDN;
381 #else
382 	    goto not_there;
383 #endif
384 	if (strEQ(name, "NI_NUMERICHOST"))
385 #ifdef NI_NUMERICHOST
386 	    return NI_NUMERICHOST;
387 #else
388 	    goto not_there;
389 #endif
390 	if (strEQ(name, "NI_NAMEREQD"))
391 #ifdef NI_NAMEREQD
392 	    return NI_NAMEREQD;
393 #else
394 	    goto not_there;
395 #endif
396 	if (strEQ(name, "NI_NUMERICSERV"))
397 #ifdef NI_NUMERICSERV
398 	    return NI_NUMERICSERV;
399 #else
400 	    goto not_there;
401 #endif
402 	if (strEQ(name, "NI_DGRAM"))
403 #ifdef NI_DGRAM
404 	    return NI_DGRAM;
405 #else
406 	    goto not_there;
407 #endif
408 	if (strEQ(name, "NI_WITHSCOPEID"))
409 #ifdef NI_WITHSCOPEID
410 	    return NI_WITHSCOPEID;
411 #else
412 	    goto not_there;
413 #endif
414  	break;
415     case 'P':
416 	if (strEQ(name, "PF_INET6"))
417 #ifdef PF_INET6
418 	    return PF_INET6;
419 #else
420 	    goto not_there;
421 #endif
422 	break;
423     }
424     errno = EINVAL;
425     return 0;
426 
427 not_there:
428     errno = ENOENT;
429     return 0;
430 }
431 
432 
433 MODULE = Socket6	PACKAGE = Socket6
434 
435 double
436 constant(name,arg)
437 	char *		name
438 	int		arg
439 
440 void
441 gethostbyname2(host, af)
442 	char *	host;
443 	int	af;
444 	PPCODE:
445 {
446 #ifdef HAVE_GETHOSTBYNAME2
447 	struct hostent *phe;
448 	int count, i;
449 
450 	if ((phe = gethostbyname2(host, af)) != NULL) {
451 		for (count = 0; phe->h_addr_list[count]; ++count);
452 		EXTEND(sp, 4 + count);
453 		PUSHs(sv_2mortal(newSVpv((char *) phe->h_name,
454 					 strlen(phe->h_name))));
455 		PUSHs(sv_2mortal(newSVpv((char *) phe->h_aliases,
456 					 sizeof(char *))));
457 		PUSHs(sv_2mortal(newSViv((IV) phe->h_addrtype)));
458 		PUSHs(sv_2mortal(newSViv((IV) phe->h_length)));
459 		for (i = 0; i < count; ++i) {
460 			PUSHs(sv_2mortal(newSVpv((char *)phe->h_addr_list[i],
461 						 phe->h_length)));
462 		}
463 	}
464 #else
465 	ST(0) = (SV *) not_here("gethostbyname2");
466 #endif
467 }
468 
469 void
inet_pton(af,host)470 inet_pton(af, host)
471 	int	af
472 	char *	host
473 	CODE:
474 {
475 #ifdef HAVE_INET_PTON
476 	union {
477 #ifdef INET6_ADDRSTRLEN
478 		struct in6_addr addr6;
479 #endif
480 		struct in_addr addr4;
481 	} ip_address;
482 	int len;
483 	int ok;
484 
485 	switch (af) {
486 #ifdef INET6_ADDRSTRLEN
487 	case AF_INET6:
488 		len = sizeof(struct in6_addr);
489 		break;
490 #endif
491 	case AF_INET:
492 		len = sizeof(struct in_addr);
493 		break;
494 	default:
495 		croak("Bad address family for %s, got %d",
496 			"Socket6::inet_pton", af);
497 		break;
498 	}
499 	ok = inet_pton(af, host, &ip_address);
500 
501 	ST(0) = sv_newmortal();
502 	if (ok == 1) {
503 		sv_setpvn( ST(0), (char *)&ip_address, len );
504 	}
505 #else
506 	ST(0) = (SV *) not_here("inet_pton");
507 #endif
508 }
509 
510 void
inet_ntop(af,address_sv)511 inet_ntop(af, address_sv)
512 	int	af
513 	SV *	address_sv
514 	CODE:
515 {
516 #ifdef HAVE_INET_NTOP
517 	STRLEN addrlen, alen;
518 #ifdef INET6_ADDRSTRLEN
519 	struct in6_addr addr;
520 	char addr_str[INET6_ADDRSTRLEN];
521 #else
522 	struct in_addr addr;
523 	char addr_str[16];
524 #endif
525 	char * address = SvPV(address_sv,addrlen);
526 
527 	switch (af) {
528 	case AF_INET:
529 		alen = sizeof(struct in_addr);
530 		break;
531 #ifdef INET6_ADDRSTRLEN
532 	case AF_INET6:
533 		alen = sizeof(struct in6_addr);
534 		break;
535 #endif
536 	default:
537 		croak("Unsupported address family for %s, af is %d",
538 		      "Socket6::inet_ntop", af);
539 	}
540 
541 	/* with sanity check, just in case */
542 	if (alen > sizeof(addr) || alen != addrlen) {
543 		croak("Bad arg length for %s, length is %d, should be %d",
544 		      "Socket6::inet_ntop",
545 		      addrlen, alen);
546 	}
547 
548 	Copy( address, &addr, alen, char );
549 	addr_str[0] = 0;
550 	inet_ntop(af, &addr, addr_str, sizeof addr_str);
551 
552 	ST(0) = sv_2mortal(newSVpv(addr_str, strlen(addr_str)));
553 #else
554 	ST(0) = (SV *) not_here("inet_ntop");
555 #endif
556 }
557 
558 void
pack_sockaddr_in6(port,ip6_address)559 pack_sockaddr_in6(port,ip6_address)
560 	unsigned short	port
561 	char *	ip6_address
562 	CODE:
563 {
564 #ifdef INET6_ADDRSTRLEN
565 	struct sockaddr_in6 sin;
566 
567 	Zero( &sin, sizeof sin, char );
568 #ifdef SIN6_LEN
569 	sin.sin6_len = sizeof sin;
570 #endif
571 	sin.sin6_family = AF_INET6;
572 	sin.sin6_port = htons(port);
573 	Copy( ip6_address, &sin.sin6_addr, sizeof sin.sin6_addr, char );
574 
575 	ST(0) = sv_2mortal(newSVpv((char *)&sin, sizeof sin));
576 #else
577 	ST(0) = (SV *) not_here("pack_sockaddr_in6");
578 #endif
579 }
580 
581 void
pack_sockaddr_in6_all(port,flowinfo,ip6_address,scope_id)582 pack_sockaddr_in6_all(port,flowinfo,ip6_address,scope_id)
583 	unsigned short	port
584 	unsigned long	flowinfo
585 	char *	ip6_address
586 	unsigned long	scope_id
587 	CODE:
588 {
589 #ifdef INET6_ADDRSTRLEN
590 	struct sockaddr_in6 sin;
591 
592 	Zero( &sin, sizeof sin, char );
593 #ifdef SIN6_LEN
594 	sin.sin6_len = sizeof sin;
595 #endif
596 	sin.sin6_family = AF_INET6;
597 	sin.sin6_port = htons(port);
598 	sin.sin6_flowinfo = htonl(flowinfo);
599 	Copy( ip6_address, &sin.sin6_addr, sizeof sin.sin6_addr, char );
600 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
601 	sin.sin6_scope_id = scope_id;
602 #endif
603 
604 	ST(0) = sv_2mortal(newSVpv((char *)&sin, sizeof sin));
605 #else
606 	ST(0) = (SV *) not_here("pack_sockaddr_in6_all");
607 #endif
608 }
609 
610 void
unpack_sockaddr_in6(sin_sv)611 unpack_sockaddr_in6(sin_sv)
612 	SV *	sin_sv
613 	PPCODE:
614 {
615 #ifdef INET6_ADDRSTRLEN
616 	STRLEN sockaddrlen;
617 	struct sockaddr_in6 addr;
618 	unsigned short	port;
619 	struct in6_addr	ip6_address;
620 	char *	sin = SvPV(sin_sv,sockaddrlen);
621 	if (sockaddrlen != sizeof(addr)) {
622 		croak("Bad arg length for %s, length is %d, should be %d",
623 		      "Socket6::unpack_sockaddr_in6",
624 		      sockaddrlen, sizeof(addr));
625 	}
626 	Copy( sin, &addr,sizeof addr, char );
627 	if ( addr.sin6_family != AF_INET6 ) {
628 		croak("Bad address family for %s, got %d, should be %d",
629 		      "Socket6::unpack_sockaddr_in6",
630 		      addr.sin6_family,
631 		      AF_INET6);
632 	}
633 	port = ntohs(addr.sin6_port);
634 	ip6_address = addr.sin6_addr;
635 
636 	EXTEND(sp, 2);
637 	PUSHs(sv_2mortal(newSViv((IV) port)));
638 	PUSHs(sv_2mortal(newSVpv((char *)&ip6_address,sizeof ip6_address)));
639 #else
640 	ST(0) = (SV *) not_here("unpack_sockaddr_in6");
641 #endif
642 }
643 
644 void
unpack_sockaddr_in6_all(sin_sv)645 unpack_sockaddr_in6_all(sin_sv)
646 	SV *	sin_sv
647 	PPCODE:
648 {
649 #ifdef INET6_ADDRSTRLEN
650 	STRLEN sockaddrlen;
651 	struct sockaddr_in6 addr;
652 	unsigned short	port;
653 	unsigned long	flowinfo;
654 	struct in6_addr	ip6_address;
655 	unsigned long	scope_id;
656 	char *	sin = SvPV(sin_sv,sockaddrlen);
657 	if (sockaddrlen != sizeof(addr)) {
658 		croak("Bad arg length for %s, length is %d, should be %d",
659 		      "Socket6::unpack_sockaddr_in6",
660 		      sockaddrlen, sizeof(addr));
661 	}
662 	Copy( sin, &addr,sizeof addr, char );
663 	if ( addr.sin6_family != AF_INET6 ) {
664 		croak("Bad address family for %s, got %d, should be %d",
665 		      "Socket6::unpack_sockaddr_in6",
666 		      addr.sin6_family,
667 		      AF_INET6);
668 	}
669 	port = ntohs(addr.sin6_port);
670 	flowinfo = ntohl(addr.sin6_flowinfo);
671 	ip6_address = addr.sin6_addr;
672 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
673 	scope_id = addr.sin6_scope_id;
674 #else
675 	scope_id = 0;
676 #endif
677 
678 	EXTEND(sp, 5);
679 	PUSHs(sv_2mortal(newSViv((IV) port)));
680 	PUSHs(sv_2mortal(newSViv((IV) flowinfo)));
681 	PUSHs(sv_2mortal(newSVpv((char *)&ip6_address,sizeof ip6_address)));
682 	PUSHs(sv_2mortal(newSViv((IV) scope_id)));
683 #else
684 	ST(0) = (SV *) not_here("unpack_sockaddr_in6_all");
685 #endif
686 }
687 
688 void
in6addr_any()689 in6addr_any()
690 	CODE:
691 {
692 #ifdef INET6_ADDRSTRLEN
693 	ST(0) = sv_2mortal(newSVpv((char *)&in6addr_any, sizeof in6addr_any));
694 #else
695 	ST(0) = (SV *) not_here("in6addr_any");
696 #endif
697 }
698 
699 void
in6addr_loopback()700 in6addr_loopback()
701 	CODE:
702 {
703 #ifdef INET6_ADDRSTRLEN
704 	ST(0) = sv_2mortal(newSVpv((char *)&in6addr_loopback,
705 				   sizeof in6addr_loopback));
706 #else
707 	ST(0) = (SV *) not_here("in6addr_loopback");
708 #endif
709 }
710 
711 void
712 getaddrinfo(host,port,family=0,socktype=0,protocol=0,flags=0)
713 	char *	host
714 	char *	port
715 	int	family
716 	int	socktype
717 	int	protocol
718 	int	flags
719 	PPCODE:
720 {
721 #ifdef HAVE_GETADDRINFO
722 	struct addrinfo hints, * res;
723 	int	err;
724 	int	count;
725 	const char	*error;
726 	WSA_DECLARE;
727 
728 	Zero( &hints, sizeof hints, char );
729 	hints.ai_flags = flags;
730 	hints.ai_family = family;
731 	hints.ai_socktype = socktype;
732 	hints.ai_protocol = protocol;
733 	WSA_STARTUP();
734 	err = getaddrinfo(*host ? host : 0, *port ? port : 0, &hints, &res);
735 	WSA_CLEANUP();
736 
737 	if (err == 0) {
738 		struct addrinfo * p;
739 		count = 0;
740 		for (p = res; p; p = p->ai_next)
741 			++count;
742 		EXTEND(sp, 5 * count);
743 		for (p = res; p; p = p->ai_next) {
744 			PUSHs(sv_2mortal(newSViv((IV) p->ai_family)));
745 			PUSHs(sv_2mortal(newSViv((IV) p->ai_socktype)));
746 			PUSHs(sv_2mortal(newSViv((IV) p->ai_protocol)));
747 			PUSHs(sv_2mortal(newSVpv((char *)p->ai_addr,
748 			      p->ai_addrlen)));
749 			if (p->ai_canonname)
750 				PUSHs(sv_2mortal(newSVpv((char *)p->ai_canonname,
751 				      strlen(p->ai_canonname))));
752 			else
753 				PUSHs(&PL_sv_undef);
754 		}
755 		freeaddrinfo(res);
756 	} else  {
757 		SV *error_sv = sv_newmortal();
758 		SvUPGRADE(error_sv, SVt_PVNV);
759 		error = gai_strerror(err);
760 		sv_setpv(error_sv, error);
761 		SvIV_set(error_sv, err); SvIOK_on(error_sv);
762 		PUSHs(error_sv);
763 	}
764 #else
765 	ST(0) = (SV *) not_here("getaddrinfo");
766 #endif
767 }
768 
769 void
770 getnameinfo(sin_sv, flags = 0)
771 	SV *	sin_sv
772 	int flags;
773 	PPCODE:
774 {
775 #ifdef HAVE_GETNAMEINFO
776 	STRLEN sockaddrlen;
777 	struct sockaddr * sin = (struct sockaddr *)SvPV(sin_sv,sockaddrlen);
778 	char host[NI_MAXHOST];
779 	char port[NI_MAXSERV];
780 	int	err;
781 	const char	*error;
782 	WSA_DECLARE;
783 
784 	WSA_STARTUP();
785 	if (items < 2) {
786 		err = getnameinfo(sin, sockaddrlen, host, sizeof host,
787 				  port, sizeof port, 0);
788 		if (err)
789 			err = getnameinfo(sin, sockaddrlen, host, sizeof host,
790 					  port, sizeof port, NI_NUMERICSERV);
791 		if (err)
792 			err = getnameinfo(sin, sockaddrlen, host, sizeof host,
793 					  port, sizeof port, NI_NUMERICHOST);
794 		if (err)
795 			err = getnameinfo(sin, sockaddrlen, host, sizeof host,
796 					  port, sizeof port,
797 					  NI_NUMERICHOST|NI_NUMERICSERV);
798 	} else {
799 		err = getnameinfo(sin, sockaddrlen, host, sizeof host,
800 				  port, sizeof port, flags);
801 	}
802 	WSA_CLEANUP();
803 
804 	if (err == 0) {
805 		EXTEND(sp, 2);
806 		PUSHs(sv_2mortal(newSVpv(host, strlen(host))));
807 		PUSHs(sv_2mortal(newSVpv(port, strlen(port))));
808 	} else  {
809 		SV *error_sv = sv_newmortal();
810 		SvUPGRADE(error_sv, SVt_PVNV);
811 		error = gai_strerror(err);
812 		sv_setpv(error_sv, error);
813 		SvIV_set(error_sv, err); SvIOK_on(error_sv);
814 		PUSHs(error_sv);
815 	}
816 #else
817 	ST(0) = (SV *) not_here("getnameinfo");
818 #endif
819 }
820 
821 char *
822 gai_strerror(errcode = 0)
823 	int	errcode;
824 	CODE:
825 	RETVAL = (char *)gai_strerror(errcode);
826 	OUTPUT:
827 	RETVAL
828 
829 void
830 getipnodebyname(hostname, family=0, flags=0)
831 	char *	hostname
832 	int	family
833 	int	flags
834 	PREINIT:
835 #ifdef HAVE_GETIPNODEBYNAME
836 	struct hostent	*he;
837 	int		err;
838 	char		**p;
839 	SV		*temp, *address_ref, *alias_ref;
840 	AV		*address_list, *alias_list;
841 #endif
842 	PPCODE:
843 {
844 #ifdef HAVE_GETIPNODEBYNAME
845 	he = getipnodebyname(hostname, family, flags, &err);
846 
847 	if (err == 0) {
848 		XPUSHs(sv_2mortal(newSVpv(he->h_name, strlen(he->h_name))));
849 		XPUSHs(sv_2mortal(newSViv(he->h_addrtype)));
850 		XPUSHs(sv_2mortal(newSViv(he->h_length)));
851 
852 		address_list = newAV();
853 		for(p = he->h_addr_list; *p != NULL; p++) {
854 			temp = newSVpv(*p, he->h_length);
855 			av_push(address_list, temp);
856 		}
857 		address_ref = newRV_noinc((SV*) address_list);
858 		XPUSHs(address_ref);
859 
860 		alias_list = newAV();
861 		for(p = he->h_aliases; *p != NULL; p++) {
862 			temp = newSVpv(*p, strlen(*p));
863 			av_push(alias_list, temp);
864 		}
865 		alias_ref = newRV_noinc((SV*) alias_list);
866 		XPUSHs(alias_ref);
867 		freehostent(he);
868 	} else {
869 		XPUSHs(sv_2mortal(newSViv(err)));
870 	}
871 #else
872 	ST(0) = (SV *) not_here("getipnodebyname");
873 #endif
874 }
875 
876 void
877 getipnodebyaddr(family, address_sv)
878 	int	family
879 	SV *	address_sv
880 	PREINIT:
881 #ifdef HAVE_GETIPNODEBYADDR
882 	STRLEN		addrlen;
883 	struct hostent	*he;
884 	int		err, alen;
885 	char		**p;
886 	SV		*temp, *address_ref, *alias_ref;
887 	AV		*address_list, *alias_list;
888 	struct in6_addr	addr;
889 	char		*addr_buffer;
890 #endif
891 	PPCODE:
892 {
893 #ifdef HAVE_GETIPNODEBYADDR
894 	addr_buffer = SvPV(address_sv, addrlen);
895 
896 	switch(family) {
897 
898 	case AF_INET:
899 		alen = sizeof(struct in_addr);
900 		break;
901 	case AF_INET6:
902 		alen = sizeof(struct in6_addr);
903 		break;
904 	default:
905 		croak("Unsupported address family for %s, af is %d",
906 		    "Socket6::getipnodebyaddr", family);
907 	}
908 
909 	if (alen > sizeof(addr) || alen != addrlen) {
910 		croak("Arg length mismatch in %s, length is %d, should be %d\n",
911 		    "Socket6::getipnodebyaddr", addrlen, alen);
912 	}
913 
914 	Copy(addr_buffer, &addr, sizeof(addr), char);
915 
916 	he = getipnodebyaddr(addr_buffer, alen, family, &err);
917 
918 	if (err == 0) {
919 		XPUSHs(sv_2mortal(newSVpv(he->h_name, strlen(he->h_name))));
920 		XPUSHs(sv_2mortal(newSViv(he->h_addrtype)));
921 		XPUSHs(sv_2mortal(newSViv(he->h_length)));
922 
923 		address_list = newAV();
924 		for(p = he->h_addr_list; *p != NULL; p++) {
925 			temp = newSVpv(*p, he->h_length);
926 			av_push(address_list, temp);
927 		}
928 		address_ref = newRV_noinc((SV*) address_list);
929 		XPUSHs(address_ref);
930 
931 		alias_list = newAV();
932 		for(p = he->h_aliases; *p != NULL; p++) {
933 			temp = newSVpv(*p, strlen(*p));
934 			av_push(alias_list, temp);
935 		}
936 		alias_ref = newRV_noinc((SV*) alias_list);
937 		XPUSHs(alias_ref);
938 		freehostent(he);
939 	} else {
940 		XPUSHs(sv_2mortal(newSViv(err)));
941 	}
942 #else
943 	ST(0) = (SV *) not_here("getipnodebyaddr");
944 #endif
945 }
946