X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=ext%2FSocket%2FSocket.xs;h=e08982909b56bf8812abf0601db543d8ffe2fe71;hb=0a1f2d144e4463451f8627bd1c6ca420a59b01b0;hp=191afa6032b3b81ea66b387fabb34fedd105b32d;hpb=25f94b330371810ad4761e17a4e200e6752044c5;p=p5sagit%2Fp5-mst-13.2.git diff --git a/ext/Socket/Socket.xs b/ext/Socket/Socket.xs index 191afa6..e089829 100644 --- a/ext/Socket/Socket.xs +++ b/ext/Socket/Socket.xs @@ -1,3 +1,4 @@ +#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" @@ -6,47 +7,175 @@ # ifdef I_SYS_TYPES # include # endif -#include -#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 -#include +# 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 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 +#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. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +static int +my_inet_aton(register const char *cp, struct in_addr *addr) +{ + dTHX; + register U32 val; + register int base; + register char c; + int nparts; + const char *s; + unsigned int parts[4]; + register unsigned int *pp = parts; + + if (!cp) + return 0; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, other=decimal. + */ + val = 0; base = 10; + if (*cp == '0') { + if (*++cp == 'x' || *cp == 'X') + base = 16, cp++; + else + base = 8; + } + while ((c = *cp) != '\0') { + if (isDIGIT(c)) { + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && (s=strchr(PL_hexdigit,c))) { + val = (val << 4) + + ((s - PL_hexdigit) & 15); + cp++; + continue; + } + break; + } + if (*cp == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16-bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3 || val > 0xff) + return 0; + *pp++ = val, cp++; + } else + break; + } + /* + * Check for trailing characters. + */ + if (*cp && !isSPACE(*cp)) + return 0; + /* + * Concoct the address according to + * the number of parts specified. + */ + nparts = pp - parts + 1; /* force to an int for switch() */ + switch (nparts) { + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return 0; + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return 0; + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return 0; + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + addr->s_addr = htonl(val); + return 1; +} + +#undef inet_aton +#define inet_aton my_inet_aton + +#endif /* ! HAS_INET_ATON */ + static int -not_here(s) -char *s; +not_here(char *s) { croak("Socket::%s not implemented on this architecture", s); return -1; } static double -constant(name, arg) -char *name; -int arg; +constant(char *name, int arg) { errno = 0; switch (*name) { @@ -211,6 +340,18 @@ int arg; case 'H': break; case 'I': + if (strEQ(name, "IOV_MAX")) +#ifdef IOV_MAX + return IOV_MAX; +#else + goto not_there; +#endif + if (strEQ(name, "IPPROTO_TCP")) +#ifdef IPPROTO_TCP + return IPPROTO_TCP; +#else + goto not_there; +#endif break; case 'J': break; @@ -219,30 +360,126 @@ int arg; case 'L': break; case 'M': + if (strEQ(name, "MSG_BCAST")) +#ifdef MSG_BCAST + return MSG_BCAST; +#else + goto not_there; +#endif + 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")) -#ifdef 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_MCAST")) +#ifdef MSG_MCAST + return MSG_MCAST; +#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")) -#ifdef 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")) -#ifdef 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; @@ -399,6 +636,54 @@ int arg; 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, "SHUT_RD")) +#ifdef SHUT_RD + return SHUT_RD; +#else + return 0; +#endif + if (strEQ(name, "SHUT_RDWR")) +#ifdef SHUT_RDWR + return SHUT_RDWR; +#else + return 2; +#endif + if (strEQ(name, "SHUT_WR")) +#ifdef SHUT_WR + return SHUT_WR; +#else + return 1; +#endif if (strEQ(name, "SOCK_DGRAM")) #ifdef SOCK_DGRAM return SOCK_DGRAM; @@ -557,8 +842,44 @@ int arg; #endif break; case 'T': + if (strEQ(name, "TCP_KEEPALIVE")) +#ifdef TCP_KEEPALIVE + return TCP_KEEPALIVE; +#else + goto not_there; +#endif + if (strEQ(name, "TCP_MAXRT")) +#ifdef TCP_MAXRT + return TCP_MAXRT; +#else + goto not_there; +#endif + if (strEQ(name, "TCP_MAXSEG")) +#ifdef TCP_MAXSEG + return TCP_MAXSEG; +#else + goto not_there; +#endif + if (strEQ(name, "TCP_NODELAY")) +#ifdef TCP_NODELAY + return TCP_NODELAY; +#else + goto not_there; +#endif + if (strEQ(name, "TCP_STDURG")) +#ifdef TCP_STDURG + return TCP_STDURG; +#else + goto not_there; +#endif break; case 'U': + if (strEQ(name, "UIO_MAXIOV")) +#ifdef UIO_MAXIOV + return UIO_MAXIOV; +#else + goto not_there; +#endif break; case 'V': break; @@ -595,15 +916,15 @@ inet_aton(host) { struct in_addr ip_address; struct hostent * phe; + int ok = inet_aton(host, &ip_address); - if (phe = gethostbyname(host)) { + if (!ok && (phe = gethostbyname(host))) { Copy( phe->h_addr, &ip_address, phe->h_length, char ); - } else { - ip_address.s_addr = inet_addr(host); + ok = 1; } ST(0) = sv_newmortal(); - if(ip_address.s_addr != INADDR_NONE) { + if (ok) { sv_setpvn( ST(0), (char *)&ip_address, sizeof ip_address ); } } @@ -626,7 +947,7 @@ inet_ntoa(ip_address_sv) Copy( ip_address, &addr, sizeof addr, char ); addr_str = inet_ntoa(addr); - ST(0) = sv_2mortal(newSVpv(addr_str, strlen(addr_str))); + ST(0) = sv_2mortal(newSVpvn(addr_str, strlen(addr_str))); } void @@ -636,10 +957,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; - Copy( pathname, sun_ad.sun_path, sizeof sun_ad.sun_path, char ); - ST(0) = sv_2mortal(newSVpv((char *)&sun_ad, sizeof sun_ad)); + 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 ); +# endif + ST(0) = sv_2mortal(newSVpvn((char *)&sun_ad, sizeof sun_ad)); #else ST(0) = (SV *) not_here("pack_sockaddr_un"); #endif @@ -649,18 +999,22 @@ pack_sockaddr_un(pathname) void unpack_sockaddr_un(sun_sv) SV * sun_sv - PPCODE: + CODE: { #ifdef I_SYS_UN - STRLEN sockaddrlen; struct sockaddr_un addr; - char * sun_ad = SvPV(sun_sv,sockaddrlen); - + STRLEN sockaddrlen; + char * sun_ad = SvPV(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 ); @@ -669,8 +1023,11 @@ unpack_sockaddr_un(sun_sv) "Socket::unpack_sockaddr_un", addr.sun_family, AF_UNIX); - } - ST(0) = sv_2mortal(newSVpv(addr.sun_path, strlen(addr.sun_path))); + } + e = addr.sun_path; + while (*e && e < addr.sun_path + sizeof addr.sun_path) + ++e; + ST(0) = sv_2mortal(newSVpvn(addr.sun_path, e - addr.sun_path)); #else ST(0) = (SV *) not_here("unpack_sockaddr_un"); #endif @@ -678,7 +1035,7 @@ unpack_sockaddr_un(sun_sv) void pack_sockaddr_in(port,ip_address) - short port + unsigned short port char * ip_address CODE: { @@ -689,7 +1046,7 @@ pack_sockaddr_in(port,ip_address) 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)); + ST(0) = sv_2mortal(newSVpvn((char *)&sin, sizeof sin)); } void @@ -699,7 +1056,7 @@ unpack_sockaddr_in(sin_sv) { STRLEN sockaddrlen; struct sockaddr_in addr; - short port; + unsigned short port; struct in_addr ip_address; char * sin = SvPV(sin_sv,sockaddrlen); if (sockaddrlen != sizeof(addr)) { @@ -717,9 +1074,9 @@ unpack_sockaddr_in(sin_sv) port = ntohs(addr.sin_port); ip_address = addr.sin_addr; - EXTEND(sp, 2); - PUSHs(sv_2mortal(newSViv(port))); - PUSHs(sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address))); + EXTEND(SP, 2); + PUSHs(sv_2mortal(newSViv((IV) port))); + PUSHs(sv_2mortal(newSVpvn((char *)&ip_address,sizeof ip_address))); } void @@ -728,7 +1085,7 @@ INADDR_ANY() { struct in_addr ip_address; ip_address.s_addr = htonl(INADDR_ANY); - ST(0) = sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address )); + ST(0) = sv_2mortal(newSVpvn((char *)&ip_address,sizeof ip_address )); } void @@ -737,7 +1094,7 @@ INADDR_LOOPBACK() { struct in_addr ip_address; ip_address.s_addr = htonl(INADDR_LOOPBACK); - ST(0) = sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address)); + ST(0) = sv_2mortal(newSVpvn((char *)&ip_address,sizeof ip_address)); } void @@ -746,5 +1103,14 @@ INADDR_NONE() { struct in_addr ip_address; ip_address.s_addr = htonl(INADDR_NONE); - ST(0) = sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address)); + ST(0) = sv_2mortal(newSVpvn((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(newSVpvn((char *)&ip_address,sizeof ip_address)); }