X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=ext%2FSocket%2FSocket.xs;h=d844775e4f1fa24263c55d8a58d8519b719db575;hb=c0bb2de79803fbbfe9a5966d43509add0c8bb4de;hp=0bd6e590570a173ab2e67d02362706c1f530a389;hpb=b4be96abee3e02e46345da5f24904c7588e0cc2d;p=p5sagit%2Fp5-mst-13.2.git diff --git a/ext/Socket/Socket.xs b/ext/Socket/Socket.xs index 0bd6e59..d844775 100644 --- a/ext/Socket/Socket.xs +++ b/ext/Socket/Socket.xs @@ -1,52 +1,76 @@ +#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" +#include + #ifndef VMS # ifdef I_SYS_TYPES # include # endif -#include -#ifdef MPE -# define PF_INET AF_INET -# define PF_UNIX AF_UNIX -# define SOCK_RAW 3 -#endif -#ifdef I_SYS_UN -#include -#endif +# include +# if defined(USE_SOCKS) && defined(I_SOCKS) +# include +# endif +# ifdef MPE +# define PF_INET AF_INET +# define PF_UNIX AF_UNIX +# define SOCK_RAW 3 +# endif +# ifdef I_SYS_UN +# include +# endif +/* XXX Configure test for +# endif # ifdef I_NETINET_IN # include # endif -#include -#ifdef I_ARPA_INET -# include -#endif +# ifdef I_NETDB +# include +# endif +# ifdef I_ARPA_INET +# include +# endif +# ifdef I_NETINET_TCP +# include +# endif #else -#include "sockadapt.h" +# include "sockadapt.h" +#endif + +#ifdef NETWARE +NETDB_DEFINE_CONTEXT +NETINET_DEFINE_CONTEXT +#endif + +#ifdef I_SYSUIO +# include #endif #ifndef AF_NBS -#undef PF_NBS +# undef PF_NBS #endif #ifndef AF_X25 -#undef PF_X25 +# undef PF_X25 #endif #ifndef INADDR_NONE -#define INADDR_NONE 0xffffffff +# define INADDR_NONE 0xffffffff #endif /* INADDR_NONE */ #ifndef INADDR_BROADCAST -#define INADDR_BROADCAST 0xffffffff +# define INADDR_BROADCAST 0xffffffff #endif /* INADDR_BROADCAST */ #ifndef INADDR_LOOPBACK -#define INADDR_LOOPBACK 0x7F000001 +# define INADDR_LOOPBACK 0x7F000001 #endif /* INADDR_LOOPBACK */ #ifndef HAS_INET_ATON -/* +/* * Check whether "cp" is a valid ascii representation * of an Internet address and convert to a binary address. * Returns 1 if the address is valid, 0 if not. @@ -56,6 +80,7 @@ static int my_inet_aton(register const char *cp, struct in_addr *addr) { + dTHX; register U32 val; register int base; register char c; @@ -64,7 +89,7 @@ my_inet_aton(register const char *cp, struct in_addr *addr) unsigned int parts[4]; register unsigned int *pp = parts; - if (!cp) + if (!cp || !*cp) return 0; for (;;) { /* @@ -86,7 +111,7 @@ my_inet_aton(register const char *cp, struct in_addr *addr) continue; } if (base == 16 && (s=strchr(PL_hexdigit,c))) { - val = (val << 4) + + val = (val << 4) + ((s - PL_hexdigit) & 15); cp++; continue; @@ -156,662 +181,41 @@ not_here(char *s) return -1; } -static double -constant(char *name, int arg) -{ - errno = 0; - switch (*name) { - case 'A': - if (strEQ(name, "AF_802")) -#ifdef AF_802 - return AF_802; -#else - goto not_there; -#endif - if (strEQ(name, "AF_APPLETALK")) -#ifdef AF_APPLETALK - return AF_APPLETALK; -#else - goto not_there; -#endif - if (strEQ(name, "AF_CCITT")) -#ifdef AF_CCITT - return AF_CCITT; -#else - goto not_there; -#endif - if (strEQ(name, "AF_CHAOS")) -#ifdef AF_CHAOS - return AF_CHAOS; -#else - goto not_there; -#endif - if (strEQ(name, "AF_DATAKIT")) -#ifdef AF_DATAKIT - return AF_DATAKIT; -#else - goto not_there; -#endif - if (strEQ(name, "AF_DECnet")) -#ifdef AF_DECnet - return AF_DECnet; -#else - goto not_there; -#endif - if (strEQ(name, "AF_DLI")) -#ifdef AF_DLI - return AF_DLI; -#else - goto not_there; -#endif - if (strEQ(name, "AF_ECMA")) -#ifdef AF_ECMA - return AF_ECMA; -#else - goto not_there; -#endif - if (strEQ(name, "AF_GOSIP")) -#ifdef AF_GOSIP - return AF_GOSIP; -#else - goto not_there; -#endif - if (strEQ(name, "AF_HYLINK")) -#ifdef AF_HYLINK - return AF_HYLINK; -#else - goto not_there; -#endif - if (strEQ(name, "AF_IMPLINK")) -#ifdef AF_IMPLINK - return AF_IMPLINK; -#else - goto not_there; -#endif - if (strEQ(name, "AF_INET")) -#ifdef AF_INET - return AF_INET; -#else - goto not_there; -#endif - if (strEQ(name, "AF_LAT")) -#ifdef AF_LAT - return AF_LAT; -#else - goto not_there; -#endif - if (strEQ(name, "AF_MAX")) -#ifdef AF_MAX - return AF_MAX; -#else - goto not_there; -#endif - if (strEQ(name, "AF_NBS")) -#ifdef AF_NBS - return AF_NBS; -#else - goto not_there; -#endif - if (strEQ(name, "AF_NIT")) -#ifdef AF_NIT - return AF_NIT; -#else - goto not_there; -#endif - if (strEQ(name, "AF_NS")) -#ifdef AF_NS - return AF_NS; -#else - goto not_there; -#endif - if (strEQ(name, "AF_OSI")) -#ifdef AF_OSI - return AF_OSI; -#else - goto not_there; -#endif - if (strEQ(name, "AF_OSINET")) -#ifdef AF_OSINET - return AF_OSINET; -#else - goto not_there; -#endif - if (strEQ(name, "AF_PUP")) -#ifdef AF_PUP - return AF_PUP; -#else - goto not_there; -#endif - if (strEQ(name, "AF_SNA")) -#ifdef AF_SNA - return AF_SNA; -#else - goto not_there; -#endif - if (strEQ(name, "AF_UNIX")) -#ifdef AF_UNIX - return AF_UNIX; -#else - goto not_there; -#endif - if (strEQ(name, "AF_UNSPEC")) -#ifdef AF_UNSPEC - return AF_UNSPEC; -#else - goto not_there; -#endif - if (strEQ(name, "AF_X25")) -#ifdef AF_X25 - return AF_X25; -#else - goto not_there; -#endif - break; - case 'B': - break; - case 'C': - break; - case 'D': - break; - case 'E': - break; - case 'F': - break; - case 'G': - break; - case 'H': - break; - case 'I': - break; - case 'J': - break; - case 'K': - break; - case 'L': - break; - case 'M': - if (strEQ(name, "MSG_CTLFLAGS")) -#ifdef MSG_CTLFLAGS - return MSG_CTLFLAGS; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_CTLIGNORE")) -#ifdef MSG_CTLIGNORE - return MSG_CTLIGNORE; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_CTRUNC")) -#if defined(MSG_TRUNC) || defined(HAS_MSG_CTRUNC) /* might be an enum */ - return MSG_CTRUNC; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_DONTROUTE")) -#if defined(MSG_DONTROUTE) || defined(HAS_MSG_DONTROUTE) /* might be an enum */ - return MSG_DONTROUTE; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_DONTWAIT")) -#ifdef MSG_DONTWAIT - return MSG_DONTWAIT; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_EOF")) -#ifdef MSG_EOF - return MSG_EOF; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_EOR")) -#ifdef MSG_EOR - return MSG_EOR; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_ERRQUEUE")) -#ifdef MSG_ERRQUEUE - return MSG_ERRQUEUE; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_FIN")) -#ifdef MSG_FIN - return MSG_FIN; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_MAXIOVLEN")) -#ifdef MSG_MAXIOVLEN - return MSG_MAXIOVLEN; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_NOSIGNAL")) -#ifdef MSG_NOSIGNAL - return MSG_NOSIGNAL; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_OOB")) -#if defined(MSG_OOB) || defined(HAS_MSG_OOB) /* might be an enum */ - return MSG_OOB; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_PEEK")) -#if defined(MSG_PEEK) || defined(HAS_MSG_PEEK) /* might be an enum */ - return MSG_PEEK; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_PROXY")) -#if defined(MSG_PROXY) || defined(HAS_MSG_PROXY) /* might be an enum */ - return MSG_PROXY; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_RST")) -#ifdef MSG_RST - return MSG_RST; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_SYN")) -#ifdef MSG_SYN - return MSG_SYN; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_TRUNC")) -#ifdef MSG_TRUNC - return MSG_TRUNC; -#else - goto not_there; -#endif - if (strEQ(name, "MSG_WAITALL")) -#ifdef MSG_WAITALL - return MSG_WAITALL; -#else - goto not_there; -#endif - break; - case 'N': - break; - case 'O': - break; - case 'P': - if (strEQ(name, "PF_802")) -#ifdef PF_802 - return PF_802; -#else - goto not_there; -#endif - if (strEQ(name, "PF_APPLETALK")) -#ifdef PF_APPLETALK - return PF_APPLETALK; -#else - goto not_there; -#endif - if (strEQ(name, "PF_CCITT")) -#ifdef PF_CCITT - return PF_CCITT; -#else - goto not_there; -#endif - if (strEQ(name, "PF_CHAOS")) -#ifdef PF_CHAOS - return PF_CHAOS; -#else - goto not_there; -#endif - if (strEQ(name, "PF_DATAKIT")) -#ifdef PF_DATAKIT - return PF_DATAKIT; -#else - goto not_there; -#endif - if (strEQ(name, "PF_DECnet")) -#ifdef PF_DECnet - return PF_DECnet; -#else - goto not_there; -#endif - if (strEQ(name, "PF_DLI")) -#ifdef PF_DLI - return PF_DLI; -#else - goto not_there; -#endif - if (strEQ(name, "PF_ECMA")) -#ifdef PF_ECMA - return PF_ECMA; -#else - goto not_there; -#endif - if (strEQ(name, "PF_GOSIP")) -#ifdef PF_GOSIP - return PF_GOSIP; -#else - goto not_there; -#endif - if (strEQ(name, "PF_HYLINK")) -#ifdef PF_HYLINK - return PF_HYLINK; -#else - goto not_there; -#endif - if (strEQ(name, "PF_IMPLINK")) -#ifdef PF_IMPLINK - return PF_IMPLINK; -#else - goto not_there; -#endif - if (strEQ(name, "PF_INET")) -#ifdef PF_INET - return PF_INET; -#else - goto not_there; -#endif - if (strEQ(name, "PF_LAT")) -#ifdef PF_LAT - return PF_LAT; -#else - goto not_there; -#endif - if (strEQ(name, "PF_MAX")) -#ifdef PF_MAX - return PF_MAX; -#else - goto not_there; -#endif - if (strEQ(name, "PF_NBS")) -#ifdef PF_NBS - return PF_NBS; -#else - goto not_there; -#endif - if (strEQ(name, "PF_NIT")) -#ifdef PF_NIT - return PF_NIT; -#else - goto not_there; -#endif - if (strEQ(name, "PF_NS")) -#ifdef PF_NS - return PF_NS; -#else - goto not_there; -#endif - if (strEQ(name, "PF_OSI")) -#ifdef PF_OSI - return PF_OSI; -#else - goto not_there; -#endif - if (strEQ(name, "PF_OSINET")) -#ifdef PF_OSINET - return PF_OSINET; -#else - goto not_there; -#endif - if (strEQ(name, "PF_PUP")) -#ifdef PF_PUP - return PF_PUP; -#else - goto not_there; -#endif - if (strEQ(name, "PF_SNA")) -#ifdef PF_SNA - return PF_SNA; -#else - goto not_there; -#endif - if (strEQ(name, "PF_UNIX")) -#ifdef PF_UNIX - return PF_UNIX; -#else - goto not_there; -#endif - if (strEQ(name, "PF_UNSPEC")) -#ifdef PF_UNSPEC - return PF_UNSPEC; -#else - goto not_there; -#endif - if (strEQ(name, "PF_X25")) -#ifdef PF_X25 - return PF_X25; -#else - goto not_there; -#endif - break; - case 'Q': - break; - case 'R': - break; - case 'S': - if (strEQ(name, "SCM_CONNECT")) -#ifdef SCM_CONNECT - return SCM_CONNECT; -#else - goto not_there; -#endif - if (strEQ(name, "SCM_CREDENTIALS")) -#ifdef SCM_CREDENTIALS - return SCM_CREDENTIALS; -#else - goto not_there; -#endif - if (strEQ(name, "SCM_CREDS")) -#ifdef SCM_CREDS - return SCM_CREDS; -#else - goto not_there; -#endif - if (strEQ(name, "SCM_RIGHTS")) -#if defined(SCM_RIGHTS) || defined(HAS_SCM_RIGHTS) /* might be an enum */ - return SCM_RIGHTS; -#else - goto not_there; -#endif - if (strEQ(name, "SCM_TIMESTAMP")) -#ifdef SCM_TIMESTAMP - return SCM_TIMESTAMP; -#else - goto not_there; -#endif - if (strEQ(name, "SOCK_DGRAM")) -#ifdef SOCK_DGRAM - return SOCK_DGRAM; -#else - goto not_there; -#endif - if (strEQ(name, "SOCK_RAW")) -#ifdef SOCK_RAW - return SOCK_RAW; -#else - goto not_there; -#endif - if (strEQ(name, "SOCK_RDM")) -#ifdef SOCK_RDM - return SOCK_RDM; -#else - goto not_there; -#endif - if (strEQ(name, "SOCK_SEQPACKET")) -#ifdef SOCK_SEQPACKET - return SOCK_SEQPACKET; -#else - goto not_there; -#endif - if (strEQ(name, "SOCK_STREAM")) -#ifdef SOCK_STREAM - return SOCK_STREAM; -#else - goto not_there; -#endif - if (strEQ(name, "SOL_SOCKET")) -#ifdef SOL_SOCKET - return SOL_SOCKET; -#else - goto not_there; -#endif - if (strEQ(name, "SOMAXCONN")) -#ifdef SOMAXCONN - return SOMAXCONN; -#else - goto not_there; -#endif - if (strEQ(name, "SO_ACCEPTCONN")) -#ifdef SO_ACCEPTCONN - return SO_ACCEPTCONN; -#else - goto not_there; -#endif - if (strEQ(name, "SO_BROADCAST")) -#ifdef SO_BROADCAST - return SO_BROADCAST; -#else - goto not_there; -#endif - if (strEQ(name, "SO_DEBUG")) -#ifdef SO_DEBUG - return SO_DEBUG; -#else - goto not_there; -#endif - if (strEQ(name, "SO_DONTLINGER")) -#ifdef SO_DONTLINGER - return SO_DONTLINGER; -#else - goto not_there; -#endif - if (strEQ(name, "SO_DONTROUTE")) -#ifdef SO_DONTROUTE - return SO_DONTROUTE; -#else - goto not_there; -#endif - if (strEQ(name, "SO_ERROR")) -#ifdef SO_ERROR - return SO_ERROR; -#else - goto not_there; -#endif - if (strEQ(name, "SO_KEEPALIVE")) -#ifdef SO_KEEPALIVE - return SO_KEEPALIVE; -#else - goto not_there; -#endif - if (strEQ(name, "SO_LINGER")) -#ifdef SO_LINGER - return SO_LINGER; -#else - goto not_there; -#endif - if (strEQ(name, "SO_OOBINLINE")) -#ifdef SO_OOBINLINE - return SO_OOBINLINE; -#else - goto not_there; -#endif - if (strEQ(name, "SO_RCVBUF")) -#ifdef SO_RCVBUF - return SO_RCVBUF; -#else - goto not_there; -#endif - if (strEQ(name, "SO_RCVLOWAT")) -#ifdef SO_RCVLOWAT - return SO_RCVLOWAT; -#else - goto not_there; -#endif - if (strEQ(name, "SO_RCVTIMEO")) -#ifdef SO_RCVTIMEO - return SO_RCVTIMEO; -#else - goto not_there; -#endif - if (strEQ(name, "SO_REUSEADDR")) -#ifdef SO_REUSEADDR - return SO_REUSEADDR; -#else - goto not_there; -#endif - if (strEQ(name, "SO_REUSEPORT")) -#ifdef SO_REUSEPORT - return SO_REUSEPORT; -#else - goto not_there; -#endif - if (strEQ(name, "SO_SNDBUF")) -#ifdef SO_SNDBUF - return SO_SNDBUF; -#else - goto not_there; -#endif - if (strEQ(name, "SO_SNDLOWAT")) -#ifdef SO_SNDLOWAT - return SO_SNDLOWAT; -#else - goto not_there; -#endif - if (strEQ(name, "SO_SNDTIMEO")) -#ifdef SO_SNDTIMEO - return SO_SNDTIMEO; -#else - goto not_there; -#endif - if (strEQ(name, "SO_TYPE")) -#ifdef SO_TYPE - return SO_TYPE; -#else - goto not_there; -#endif - if (strEQ(name, "SO_USELOOPBACK")) -#ifdef SO_USELOOPBACK - return SO_USELOOPBACK; -#else - goto not_there; -#endif - break; - case 'T': - break; - case 'U': - break; - case 'V': - break; - case 'W': - break; - case 'X': - break; - case 'Y': - break; - case 'Z': - break; - } - errno = EINVAL; - return 0; - -not_there: - errno = ENOENT; - return 0; -} - +#define PERL_IN_ADDR_S_ADDR_SIZE 4 + +/* +* Bad assumptions possible here. +* +* Bad Assumption 1: struct in_addr has no other fields +* than the s_addr (which is the field we care about +* in here, really). However, we can be fed either 4-byte +* addresses (from pack("N", ...), or va.b.c.d, or ...), +* or full struct in_addrs (from e.g. pack_sockaddr_in()), +* which may or may not be 4 bytes in size. +* +* Bad Assumption 2: the s_addr field is a simple type +* (such as an int, u_int32_t). It can be a bit field, +* in which case using & (address-of) on it or taking sizeof() +* wouldn't go over too well. (Those are not attempted +* now but in case someone thinks to change the below code +* to use addr.s_addr instead of addr, you have been warned.) +* +* Bad Assumption 3: the s_addr is the first field in +* an in_addr, or that its bytes are the first bytes in +* an in_addr. +* +* These bad assumptions are wrong in UNICOS which has +* struct in_addr { struct { u_long st_addr:32; } s_da }; +* #define s_addr s_da.st_addr +* and u_long is 64 bits. +* +* --jhi */ + +#include "const-c.inc" MODULE = Socket PACKAGE = Socket -double -constant(name,arg) - char * name - int arg - +INCLUDE: const-xs.inc void inet_aton(host) @@ -820,7 +224,10 @@ inet_aton(host) { struct in_addr ip_address; struct hostent * phe; - int ok = inet_aton(host, &ip_address); + int ok = + (host != NULL) && + (*host != '\0') && + inet_aton(host, &ip_address); if (!ok && (phe = gethostbyname(host))) { Copy( phe->h_addr, &ip_address, phe->h_length, char ); @@ -828,10 +235,9 @@ inet_aton(host) } ST(0) = sv_newmortal(); - if (ok) { + if (ok) sv_setpvn( ST(0), (char *)&ip_address, sizeof ip_address ); } - } void inet_ntoa(ip_address_sv) @@ -841,18 +247,47 @@ inet_ntoa(ip_address_sv) STRLEN addrlen; struct in_addr addr; char * addr_str; - char * ip_address = SvPV(ip_address_sv,addrlen); - if (addrlen != sizeof(addr)) { - croak("Bad arg length for %s, length is %d, should be %d", - "Socket::inet_ntoa", - addrlen, sizeof(addr)); + char * ip_address; + if (DO_UTF8(ip_address_sv) && !sv_utf8_downgrade(ip_address_sv, 1)) + croak("Wide character in Socket::inet_ntoa"); + ip_address = SvPVbyte(ip_address_sv, addrlen); + if (addrlen == sizeof(addr) || addrlen == 4) + addr.s_addr = + (ip_address[0] & 0xFF) << 24 | + (ip_address[1] & 0xFF) << 16 | + (ip_address[2] & 0xFF) << 8 | + (ip_address[3] & 0xFF); + else + croak("Bad arg length for %s, length is %d, should be %d", + "Socket::inet_ntoa", + addrlen, sizeof(addr)); + /* We could use inet_ntoa() but that is broken + * in HP-UX + GCC + 64bitint (returns "0.0.0.0"), + * so let's use this sprintf() workaround everywhere. + * This is also more threadsafe than using inet_ntoa(). */ + New(1138, addr_str, 4 * 3 + 3 + 1, char); /* IPv6? */ + sprintf(addr_str, "%d.%d.%d.%d", + ((addr.s_addr >> 24) & 0xFF), + ((addr.s_addr >> 16) & 0xFF), + ((addr.s_addr >> 8) & 0xFF), + ( addr.s_addr & 0xFF)); + ST(0) = sv_2mortal(newSVpvn(addr_str, strlen(addr_str))); + Safefree(addr_str); } - Copy( ip_address, &addr, sizeof addr, char ); - addr_str = inet_ntoa(addr); - - ST(0) = sv_2mortal(newSVpv(addr_str, strlen(addr_str))); +void +sockaddr_family(sockaddr) + SV * sockaddr + PREINIT: + STRLEN sockaddr_len; + char *sockaddr_pv = SvPVbyte(sockaddr, sockaddr_len); + CODE: + if (sockaddr_len < offsetof(struct sockaddr, sa_data)) { + croak("Bad arg length for %s, length is %d, should be at least %d", + "Socket::sockaddr_family", sockaddr_len, + offsetof(struct sockaddr, sa_data)); } + ST(0) = sv_2mortal(newSViv(((struct sockaddr*)sockaddr_pv)->sa_family)); void pack_sockaddr_un(pathname) @@ -862,13 +297,39 @@ pack_sockaddr_un(pathname) #ifdef I_SYS_UN struct sockaddr_un sun_ad; /* fear using sun */ STRLEN len; + Zero( &sun_ad, sizeof sun_ad, char ); sun_ad.sun_family = AF_UNIX; len = strlen(pathname); if (len > sizeof(sun_ad.sun_path)) len = sizeof(sun_ad.sun_path); +# ifdef OS2 /* Name should start with \socket\ and contain backslashes! */ + { + int off; + char *s, *e; + + if (pathname[0] != '/' && pathname[0] != '\\') + croak("Relative UNIX domain socket name '%s' unsupported", pathname); + else if (len < 8 + || pathname[7] != '/' && pathname[7] != '\\' + || !strnicmp(pathname + 1, "socket", 6)) + off = 7; + else + off = 0; /* Preserve names starting with \socket\ */ + Copy( "\\socket", sun_ad.sun_path, off, char); + Copy( pathname, sun_ad.sun_path + off, len, char ); + + s = sun_ad.sun_path + off - 1; + e = s + len + 1; + while (++s < e) + if (*s = '/') + *s = '\\'; + } +# else /* !( defined OS2 ) */ Copy( pathname, sun_ad.sun_path, len, char ); - ST(0) = sv_2mortal(newSVpv((char *)&sun_ad, sizeof sun_ad)); +# endif + if (0) not_here("dummy"); + ST(0) = sv_2mortal(newSVpvn((char *)&sun_ad, sizeof sun_ad)); #else ST(0) = (SV *) not_here("pack_sockaddr_un"); #endif @@ -883,14 +344,17 @@ unpack_sockaddr_un(sun_sv) #ifdef I_SYS_UN struct sockaddr_un addr; STRLEN sockaddrlen; - char * sun_ad = SvPV(sun_sv,sockaddrlen); + char * sun_ad = SvPVbyte(sun_sv,sockaddrlen); char * e; - +# ifndef __linux__ + /* On Linux sockaddrlen on sockets returned by accept, recvfrom, + getpeername and getsockname is not equal to sizeof(addr). */ if (sockaddrlen != sizeof(addr)) { croak("Bad arg length for %s, length is %d, should be %d", "Socket::unpack_sockaddr_un", sockaddrlen, sizeof(addr)); } +# endif Copy( sun_ad, &addr, sizeof addr, char ); @@ -903,26 +367,40 @@ unpack_sockaddr_un(sun_sv) e = addr.sun_path; while (*e && e < addr.sun_path + sizeof addr.sun_path) ++e; - ST(0) = sv_2mortal(newSVpv(addr.sun_path, e - addr.sun_path)); + ST(0) = sv_2mortal(newSVpvn(addr.sun_path, e - addr.sun_path)); #else ST(0) = (SV *) not_here("unpack_sockaddr_un"); #endif } void -pack_sockaddr_in(port,ip_address) +pack_sockaddr_in(port, ip_address_sv) unsigned short port - char * ip_address + SV * ip_address_sv CODE: { struct sockaddr_in sin; - + struct in_addr addr; + STRLEN addrlen; + char * ip_address; + if (DO_UTF8(ip_address_sv) && !sv_utf8_downgrade(ip_address_sv, 1)) + croak("Wide character in Socket::pack_sockaddr_in"); + ip_address = SvPVbyte(ip_address_sv, addrlen); + if (addrlen == sizeof(addr) || addrlen == 4) + addr.s_addr = + (ip_address[0] & 0xFF) << 24 | + (ip_address[1] & 0xFF) << 16 | + (ip_address[2] & 0xFF) << 8 | + (ip_address[3] & 0xFF); + else + croak("Bad arg length for %s, length is %d, should be %d", + "Socket::pack_sockaddr_in", + addrlen, sizeof(addr)); Zero( &sin, sizeof sin, char ); sin.sin_family = AF_INET; sin.sin_port = htons(port); - Copy( ip_address, &sin.sin_addr, sizeof sin.sin_addr, char ); - - ST(0) = sv_2mortal(newSVpv((char *)&sin, sizeof sin)); + sin.sin_addr.s_addr = htonl(addr.s_addr); + ST(0) = sv_2mortal(newSVpvn((char *)&sin, sizeof sin)); } void @@ -933,8 +411,8 @@ unpack_sockaddr_in(sin_sv) STRLEN sockaddrlen; struct sockaddr_in addr; unsigned short port; - struct in_addr ip_address; - char * sin = SvPV(sin_sv,sockaddrlen); + struct in_addr ip_address; + char * sin = SvPVbyte(sin_sv,sockaddrlen); if (sockaddrlen != sizeof(addr)) { croak("Bad arg length for %s, length is %d, should be %d", "Socket::unpack_sockaddr_in", @@ -946,47 +424,11 @@ unpack_sockaddr_in(sin_sv) "Socket::unpack_sockaddr_in", addr.sin_family, AF_INET); - } + } port = ntohs(addr.sin_port); ip_address = addr.sin_addr; EXTEND(SP, 2); PUSHs(sv_2mortal(newSViv((IV) port))); - PUSHs(sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address))); - } - -void -INADDR_ANY() - CODE: - { - struct in_addr ip_address; - ip_address.s_addr = htonl(INADDR_ANY); - ST(0) = sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address )); - } - -void -INADDR_LOOPBACK() - CODE: - { - struct in_addr ip_address; - ip_address.s_addr = htonl(INADDR_LOOPBACK); - ST(0) = sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address)); - } - -void -INADDR_NONE() - CODE: - { - struct in_addr ip_address; - ip_address.s_addr = htonl(INADDR_NONE); - ST(0) = sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address)); - } - -void -INADDR_BROADCAST() - CODE: - { - struct in_addr ip_address; - ip_address.s_addr = htonl(INADDR_BROADCAST); - ST(0) = sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address)); + PUSHs(sv_2mortal(newSVpvn((char *)&ip_address, sizeof ip_address))); }