X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=ext%2FSocket%2FSocket.xs;h=1c541d7cef2650ffecfae4551a3f691c58d1ecdb;hb=5b8dae3fb0c7cd61d5a928efa0f69f243928e61b;hp=e799c81e894993370eaaca9b0f87b00d497fef7f;hpb=4633a7c4bad06b471d9310620b7fe8ddd158cccd;p=p5sagit%2Fp5-mst-13.2.git diff --git a/ext/Socket/Socket.xs b/ext/Socket/Socket.xs index e799c81..1c541d7 100644 --- a/ext/Socket/Socket.xs +++ b/ext/Socket/Socket.xs @@ -7,12 +7,21 @@ # 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 # ifdef I_NETINET_IN # include # endif #include -#include +#ifdef I_ARPA_INET +# include +#endif #else #include "sockadapt.h" #endif @@ -28,23 +37,127 @@ #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif /* INADDR_NONE */ +#ifndef INADDR_BROADCAST +#define INADDR_BROADCAST 0xffffffff +#endif /* INADDR_BROADCAST */ #ifndef INADDR_LOOPBACK #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 -not_here(s) -char *s; +my_inet_aton(register const char *cp, struct in_addr *addr) +{ + 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(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) { @@ -217,30 +330,114 @@ int arg; 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")) -#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_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; @@ -397,6 +594,36 @@ 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_CREDENTIALSS; +#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; @@ -593,15 +820,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 ); } } @@ -632,21 +859,32 @@ pack_sockaddr_un(pathname) char * pathname CODE: { +#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 ); + len = strlen(pathname); + if (len > sizeof(sun_ad.sun_path)) + len = sizeof(sun_ad.sun_path); + Copy( pathname, sun_ad.sun_path, len, char ); ST(0) = sv_2mortal(newSVpv((char *)&sun_ad, sizeof sun_ad)); +#else + ST(0) = (SV *) not_here("pack_sockaddr_un"); +#endif + } void unpack_sockaddr_un(sun_sv) SV * sun_sv - PPCODE: + CODE: { - STRLEN sockaddrlen; +#ifdef I_SYS_UN struct sockaddr_un addr; - char * sun_ad = SvPV(sun_sv,sockaddrlen); + STRLEN sockaddrlen; + char * sun_ad = SvPV(sun_sv,sockaddrlen); + char * e; if (sockaddrlen != sizeof(addr)) { croak("Bad arg length for %s, length is %d, should be %d", @@ -661,13 +899,19 @@ 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(newSVpv(addr.sun_path, e - addr.sun_path)); +#else + ST(0) = (SV *) not_here("unpack_sockaddr_un"); +#endif } void pack_sockaddr_in(port,ip_address) - short port + unsigned short port char * ip_address CODE: { @@ -688,7 +932,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)) { @@ -706,8 +950,8 @@ unpack_sockaddr_in(sin_sv) port = ntohs(addr.sin_port); ip_address = addr.sin_addr; - EXTEND(sp, 2); - PUSHs(sv_2mortal(newSViv(port))); + EXTEND(SP, 2); + PUSHs(sv_2mortal(newSViv((IV) port))); PUSHs(sv_2mortal(newSVpv((char *)&ip_address,sizeof ip_address))); } @@ -737,3 +981,12 @@ INADDR_NONE() 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)); + }