#include "perl.h"
#include "XSUB.h"
+#include <stddef.h>
+
#ifndef VMS
# ifdef I_SYS_TYPES
# include <sys/types.h>
# endif
-# include <sys/socket.h>
+# if !defined(ultrix) /* Avoid double definition. */
+# include <sys/socket.h>
+# endif
# if defined(USE_SOCKS) && defined(I_SOCKS)
# include <socks.h>
# endif
# if defined(NeXT) || defined(__NeXT__)
# include <netinet/in_systm.h>
# endif
-# ifdef I_NETINET_IN
+# if defined(__sgi) && !defined(AF_LINK) && defined(PF_LINK) && PF_LINK == AF_LNK
+# undef PF_LINK
+# endif
+# if defined(I_NETINET_IN) || defined(__ultrix__)
# include <netinet/in.h>
# endif
# ifdef I_NETDB
-# include <netdb.h>
+# if !defined(ultrix) /* Avoid double definition. */
+# include <netdb.h>
+# endif
# endif
# ifdef I_ARPA_INET
# include <arpa/inet.h>
static int
-not_here(char *s)
+not_here(const char *s)
{
croak("Socket::%s not implemented on this architecture", s);
return -1;
*
* --jhi */
-#include "constants.c"
+#include "const-c.inc"
MODULE = Socket PACKAGE = Socket
-INCLUDE: constants.xs
+INCLUDE: const-xs.inc
void
inet_aton(host)
{
struct in_addr ip_address;
struct hostent * phe;
- int ok =
- (host != NULL) &&
- (*host != '\0') &&
- inet_aton(host, &ip_address);
+ int ok = (*host != '\0') && inet_aton(host, &ip_address);
- if (!ok && (phe = gethostbyname(host))) {
+ if (!ok && (phe = gethostbyname(host)) &&
+ phe->h_addrtype == AF_INET && phe->h_length == 4) {
Copy( phe->h_addr, &ip_address, phe->h_length, char );
ok = 1;
}
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 = SvPV(ip_address_sv, addrlen);
+ ip_address = SvPVbyte(ip_address_sv, addrlen);
if (addrlen == sizeof(addr) || addrlen == 4)
addr.s_addr =
(ip_address[0] & 0xFF) << 24 |
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. */
- New(1138, addr_str, 4 * 3 + 3 + 1, char);
+ * so let's use this sprintf() workaround everywhere.
+ * This is also more threadsafe than using inet_ntoa(). */
+ Newx(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)));
+ ST(0) = newSVpvn_flags(addr_str, strlen(addr_str), SVs_TEMP);
Safefree(addr_str);
}
SV * sockaddr
PREINIT:
STRLEN sockaddr_len;
- char *sockaddr_pv = SvPV(sockaddr, 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",
void
pack_sockaddr_un(pathname)
- char * pathname
+ SV * pathname
CODE:
{
#ifdef I_SYS_UN
struct sockaddr_un sun_ad; /* fear using sun */
STRLEN len;
+ char * pathname_pv;
+ int addr_len;
Zero( &sun_ad, sizeof sun_ad, char );
sun_ad.sun_family = AF_UNIX;
- len = strlen(pathname);
+ pathname_pv = SvPV(pathname,len);
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);
+ if (pathname_pv[0] != '/' && pathname_pv[0] != '\\')
+ croak("Relative UNIX domain socket name '%s' unsupported",
+ pathname_pv);
else if (len < 8
- || pathname[7] != '/' && pathname[7] != '\\'
- || !strnicmp(pathname + 1, "socket", 6))
+ || pathname_pv[7] != '/' && pathname_pv[7] != '\\'
+ || !strnicmp(pathname_pv + 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 );
+ Copy( pathname_pv, sun_ad.sun_path + off, len, char );
s = sun_ad.sun_path + off - 1;
e = s + len + 1;
*s = '\\';
}
# else /* !( defined OS2 ) */
- Copy( pathname, sun_ad.sun_path, len, char );
+ Copy( pathname_pv, sun_ad.sun_path, len, char );
# endif
if (0) not_here("dummy");
- ST(0) = sv_2mortal(newSVpvn((char *)&sun_ad, sizeof sun_ad));
+ if (len > 1 && sun_ad.sun_path[0] == '\0') {
+ /* Linux-style abstract-namespace socket.
+ * The name is not a file name, but an array of arbitrary
+ * character, starting with \0 and possibly including \0s,
+ * therefore the length of the structure must denote the
+ * end of that character array */
+ addr_len = (char *)&(sun_ad.sun_path) - (char *)&sun_ad + len;
+ } else {
+ addr_len = sizeof sun_ad;
+ }
+ ST(0) = newSVpvn_flags((char *)&sun_ad, addr_len, SVs_TEMP);
#else
ST(0) = (SV *) not_here("pack_sockaddr_un");
#endif
#ifdef I_SYS_UN
struct sockaddr_un addr;
STRLEN sockaddrlen;
- char * sun_ad = SvPV(sun_sv,sockaddrlen);
- char * e;
+ char * sun_ad = SvPVbyte(sun_sv,sockaddrlen);
+ int addr_len;
# ifndef __linux__
/* On Linux sockaddrlen on sockets returned by accept, recvfrom,
getpeername and getsockname is not equal to sizeof(addr). */
addr.sun_family,
AF_UNIX);
}
- 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));
+
+ if (addr.sun_path[0] == '\0') {
+ /* Linux-style abstract socket address begins with a nul
+ * and can contain nuls. */
+ addr_len = (char *)&addr - (char *)&(addr.sun_path) + sockaddrlen;
+ } else {
+ for (addr_len = 0; addr.sun_path[addr_len]
+ && addr_len < sizeof addr.sun_path; addr_len++);
+ }
+
+ ST(0) = newSVpvn_flags(addr.sun_path, addr_len, SVs_TEMP);
#else
ST(0) = (SV *) not_here("unpack_sockaddr_un");
#endif
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 = SvPV(ip_address_sv, addrlen);
+ ip_address = SvPVbyte(ip_address_sv, addrlen);
if (addrlen == sizeof(addr) || addrlen == 4)
addr.s_addr =
(ip_address[0] & 0xFF) << 24 |
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = htonl(addr.s_addr);
- ST(0) = sv_2mortal(newSVpvn((char *)&sin, sizeof sin));
+ ST(0) = newSVpvn_flags((char *)&sin, sizeof (sin), SVs_TEMP);
}
void
struct sockaddr_in addr;
unsigned short port;
struct in_addr ip_address;
- char * sin = SvPV(sin_sv,sockaddrlen);
+ 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",
EXTEND(SP, 2);
PUSHs(sv_2mortal(newSViv((IV) port)));
- PUSHs(sv_2mortal(newSVpvn((char *)&ip_address, sizeof ip_address)));
+ PUSHs(newSVpvn_flags((char *)&ip_address, sizeof(ip_address), SVs_TEMP));
}
+
+void
+inet_ntop(af, ip_address_sv)
+ int af
+ SV * ip_address_sv
+ CODE:
+#ifdef HAS_INETNTOP
+ STRLEN addrlen, struct_size;
+ struct in6_addr addr;
+ char str[INET6_ADDRSTRLEN];
+ char *ip_address = SvPV(ip_address_sv, addrlen);
+
+ if(af == AF_INET) {
+ struct_size = sizeof(struct in_addr);
+ } else if(af == AF_INET6) {
+ struct_size = sizeof(struct in6_addr);
+ } else {
+ croak("Bad address family for Socket::inet_ntop, got %d, should be either AF_INET or AF_INET6",
+ af);
+ }
+
+ Copy( ip_address, &addr, sizeof addr, char );
+ inet_ntop(af, &addr, str, INET6_ADDRSTRLEN);
+
+ ST(0) = newSVpvn_flags(str, strlen(str), SVs_TEMP);
+#else
+ ST(0) = (SV *)not_here("inet_ntop");
+#endif
+
+void
+inet_pton(af, host)
+ int af
+ const char * host
+ CODE:
+#ifdef HAS_INETPTON
+ int ok;
+ struct in6_addr ip_address;
+ if(af != AF_INET && af != AF_INET6) {
+ croak("Bad address family for %s, got %d, should be either AF_INET or AF_INET6",
+ "Socket::inet_pton",
+ af);
+ }
+ ok = (*host != '\0') && inet_pton(af, host, &ip_address);
+
+ ST(0) = sv_newmortal();
+ if (ok) {
+ sv_setpvn( ST(0), (char *)&ip_address, sizeof ip_address );
+ }
+#else
+ ST(0) = (SV *)not_here("inet_pton");
+#endif