| 1 |
root |
1.1 |
#define PERL_NO_GET_CONTEXT |
| 2 |
|
|
#include "EXTERN.h" |
| 3 |
|
|
#include "perl.h" |
| 4 |
|
|
#include "XSUB.h" |
| 5 |
|
|
|
| 6 |
|
|
#include <stddef.h> |
| 7 |
|
|
|
| 8 |
|
|
#ifndef VMS |
| 9 |
|
|
# ifdef I_SYS_TYPES |
| 10 |
|
|
# include <sys/types.h> |
| 11 |
|
|
# endif |
| 12 |
|
|
# if !defined(ultrix) /* Avoid double definition. */ |
| 13 |
|
|
# include <sys/socket.h> |
| 14 |
|
|
# endif |
| 15 |
|
|
# if defined(USE_SOCKS) && defined(I_SOCKS) |
| 16 |
|
|
# include <socks.h> |
| 17 |
|
|
# endif |
| 18 |
|
|
# ifdef MPE |
| 19 |
|
|
# define PF_INET AF_INET |
| 20 |
|
|
# define PF_UNIX AF_UNIX |
| 21 |
|
|
# define SOCK_RAW 3 |
| 22 |
|
|
# endif |
| 23 |
|
|
# ifdef I_SYS_UN |
| 24 |
|
|
# include <sys/un.h> |
| 25 |
|
|
# endif |
| 26 |
|
|
/* XXX Configure test for <netinet/in_systm.h needed XXX */ |
| 27 |
|
|
# if defined(NeXT) || defined(__NeXT__) |
| 28 |
|
|
# include <netinet/in_systm.h> |
| 29 |
|
|
# endif |
| 30 |
|
|
# if defined(__sgi) && !defined(AF_LINK) && defined(PF_LINK) && PF_LINK == AF_LNK |
| 31 |
|
|
# undef PF_LINK |
| 32 |
|
|
# endif |
| 33 |
|
|
# if defined(I_NETINET_IN) || defined(__ultrix__) |
| 34 |
|
|
# include <netinet/in.h> |
| 35 |
|
|
# endif |
| 36 |
|
|
# ifdef I_NETDB |
| 37 |
|
|
# if !defined(ultrix) /* Avoid double definition. */ |
| 38 |
|
|
# include <netdb.h> |
| 39 |
|
|
# endif |
| 40 |
|
|
# endif |
| 41 |
|
|
# ifdef I_ARPA_INET |
| 42 |
|
|
# include <arpa/inet.h> |
| 43 |
|
|
# endif |
| 44 |
|
|
# ifdef I_NETINET_TCP |
| 45 |
|
|
# include <netinet/tcp.h> |
| 46 |
|
|
# endif |
| 47 |
|
|
#else |
| 48 |
|
|
# include "sockadapt.h" |
| 49 |
|
|
#endif |
| 50 |
|
|
|
| 51 |
|
|
#ifdef NETWARE |
| 52 |
|
|
NETDB_DEFINE_CONTEXT |
| 53 |
|
|
NETINET_DEFINE_CONTEXT |
| 54 |
|
|
#endif |
| 55 |
|
|
|
| 56 |
|
|
#ifdef I_SYSUIO |
| 57 |
|
|
# include <sys/uio.h> |
| 58 |
|
|
#endif |
| 59 |
|
|
|
| 60 |
|
|
#ifndef AF_NBS |
| 61 |
|
|
# undef PF_NBS |
| 62 |
|
|
#endif |
| 63 |
|
|
|
| 64 |
|
|
#ifndef AF_X25 |
| 65 |
|
|
# undef PF_X25 |
| 66 |
|
|
#endif |
| 67 |
|
|
|
| 68 |
|
|
#ifndef INADDR_NONE |
| 69 |
|
|
# define INADDR_NONE 0xffffffff |
| 70 |
|
|
#endif /* INADDR_NONE */ |
| 71 |
|
|
#ifndef INADDR_BROADCAST |
| 72 |
|
|
# define INADDR_BROADCAST 0xffffffff |
| 73 |
|
|
#endif /* INADDR_BROADCAST */ |
| 74 |
|
|
#ifndef INADDR_LOOPBACK |
| 75 |
|
|
# define INADDR_LOOPBACK 0x7F000001 |
| 76 |
|
|
#endif /* INADDR_LOOPBACK */ |
| 77 |
|
|
|
| 78 |
|
|
#ifndef HAS_INET_ATON |
| 79 |
|
|
|
| 80 |
|
|
/* |
| 81 |
|
|
* Check whether "cp" is a valid ascii representation |
| 82 |
|
|
* of an Internet address and convert to a binary address. |
| 83 |
|
|
* Returns 1 if the address is valid, 0 if not. |
| 84 |
|
|
* This replaces inet_addr, the return value from which |
| 85 |
|
|
* cannot distinguish between failure and a local broadcast address. |
| 86 |
|
|
*/ |
| 87 |
|
|
static int |
| 88 |
|
|
my_inet_aton(register const char *cp, struct in_addr *addr) |
| 89 |
|
|
{ |
| 90 |
|
|
dTHX; |
| 91 |
|
|
register U32 val; |
| 92 |
|
|
register int base; |
| 93 |
|
|
register char c; |
| 94 |
|
|
int nparts; |
| 95 |
|
|
const char *s; |
| 96 |
|
|
unsigned int parts[4]; |
| 97 |
|
|
register unsigned int *pp = parts; |
| 98 |
|
|
|
| 99 |
|
|
if (!cp || !*cp) |
| 100 |
|
|
return 0; |
| 101 |
|
|
for (;;) { |
| 102 |
|
|
/* |
| 103 |
|
|
* Collect number up to ``.''. |
| 104 |
|
|
* Values are specified as for C: |
| 105 |
|
|
* 0x=hex, 0=octal, other=decimal. |
| 106 |
|
|
*/ |
| 107 |
|
|
val = 0; base = 10; |
| 108 |
|
|
if (*cp == '0') { |
| 109 |
|
|
if (*++cp == 'x' || *cp == 'X') |
| 110 |
|
|
base = 16, cp++; |
| 111 |
|
|
else |
| 112 |
|
|
base = 8; |
| 113 |
|
|
} |
| 114 |
|
|
while ((c = *cp) != '\0') { |
| 115 |
|
|
if (isDIGIT(c)) { |
| 116 |
|
|
val = (val * base) + (c - '0'); |
| 117 |
|
|
cp++; |
| 118 |
|
|
continue; |
| 119 |
|
|
} |
| 120 |
|
|
if (base == 16 && (s=strchr(PL_hexdigit,c))) { |
| 121 |
|
|
val = (val << 4) + |
| 122 |
|
|
((s - PL_hexdigit) & 15); |
| 123 |
|
|
cp++; |
| 124 |
|
|
continue; |
| 125 |
|
|
} |
| 126 |
|
|
break; |
| 127 |
|
|
} |
| 128 |
|
|
if (*cp == '.') { |
| 129 |
|
|
/* |
| 130 |
|
|
* Internet format: |
| 131 |
|
|
* a.b.c.d |
| 132 |
|
|
* a.b.c (with c treated as 16-bits) |
| 133 |
|
|
* a.b (with b treated as 24 bits) |
| 134 |
|
|
*/ |
| 135 |
|
|
if (pp >= parts + 3 || val > 0xff) |
| 136 |
|
|
return 0; |
| 137 |
|
|
*pp++ = val, cp++; |
| 138 |
|
|
} else |
| 139 |
|
|
break; |
| 140 |
|
|
} |
| 141 |
|
|
/* |
| 142 |
|
|
* Check for trailing characters. |
| 143 |
|
|
*/ |
| 144 |
|
|
if (*cp && !isSPACE(*cp)) |
| 145 |
|
|
return 0; |
| 146 |
|
|
/* |
| 147 |
|
|
* Concoct the address according to |
| 148 |
|
|
* the number of parts specified. |
| 149 |
|
|
*/ |
| 150 |
|
|
nparts = pp - parts + 1; /* force to an int for switch() */ |
| 151 |
|
|
switch (nparts) { |
| 152 |
|
|
|
| 153 |
|
|
case 1: /* a -- 32 bits */ |
| 154 |
|
|
break; |
| 155 |
|
|
|
| 156 |
|
|
case 2: /* a.b -- 8.24 bits */ |
| 157 |
|
|
if (val > 0xffffff) |
| 158 |
|
|
return 0; |
| 159 |
|
|
val |= parts[0] << 24; |
| 160 |
|
|
break; |
| 161 |
|
|
|
| 162 |
|
|
case 3: /* a.b.c -- 8.8.16 bits */ |
| 163 |
|
|
if (val > 0xffff) |
| 164 |
|
|
return 0; |
| 165 |
|
|
val |= (parts[0] << 24) | (parts[1] << 16); |
| 166 |
|
|
break; |
| 167 |
|
|
|
| 168 |
|
|
case 4: /* a.b.c.d -- 8.8.8.8 bits */ |
| 169 |
|
|
if (val > 0xff) |
| 170 |
|
|
return 0; |
| 171 |
|
|
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); |
| 172 |
|
|
break; |
| 173 |
|
|
} |
| 174 |
|
|
addr->s_addr = htonl(val); |
| 175 |
|
|
return 1; |
| 176 |
|
|
} |
| 177 |
|
|
|
| 178 |
|
|
#undef inet_aton |
| 179 |
|
|
#define inet_aton my_inet_aton |
| 180 |
|
|
|
| 181 |
|
|
#endif /* ! HAS_INET_ATON */ |
| 182 |
|
|
|
| 183 |
|
|
|
| 184 |
|
|
static int |
| 185 |
|
|
not_here(char *s) |
| 186 |
|
|
{ |
| 187 |
|
|
croak("Socket::%s not implemented on this architecture", s); |
| 188 |
|
|
return -1; |
| 189 |
|
|
} |
| 190 |
|
|
|
| 191 |
|
|
#define PERL_IN_ADDR_S_ADDR_SIZE 4 |
| 192 |
|
|
|
| 193 |
|
|
/* |
| 194 |
|
|
* Bad assumptions possible here. |
| 195 |
|
|
* |
| 196 |
|
|
* Bad Assumption 1: struct in_addr has no other fields |
| 197 |
|
|
* than the s_addr (which is the field we care about |
| 198 |
|
|
* in here, really). However, we can be fed either 4-byte |
| 199 |
|
|
* addresses (from pack("N", ...), or va.b.c.d, or ...), |
| 200 |
|
|
* or full struct in_addrs (from e.g. pack_sockaddr_in()), |
| 201 |
|
|
* which may or may not be 4 bytes in size. |
| 202 |
|
|
* |
| 203 |
|
|
* Bad Assumption 2: the s_addr field is a simple type |
| 204 |
|
|
* (such as an int, u_int32_t). It can be a bit field, |
| 205 |
|
|
* in which case using & (address-of) on it or taking sizeof() |
| 206 |
|
|
* wouldn't go over too well. (Those are not attempted |
| 207 |
|
|
* now but in case someone thinks to change the below code |
| 208 |
|
|
* to use addr.s_addr instead of addr, you have been warned.) |
| 209 |
|
|
* |
| 210 |
|
|
* Bad Assumption 3: the s_addr is the first field in |
| 211 |
|
|
* an in_addr, or that its bytes are the first bytes in |
| 212 |
|
|
* an in_addr. |
| 213 |
|
|
* |
| 214 |
|
|
* These bad assumptions are wrong in UNICOS which has |
| 215 |
|
|
* struct in_addr { struct { u_long st_addr:32; } s_da }; |
| 216 |
|
|
* #define s_addr s_da.st_addr |
| 217 |
|
|
* and u_long is 64 bits. |
| 218 |
|
|
* |
| 219 |
|
|
* --jhi */ |
| 220 |
|
|
|
| 221 |
|
|
#include "const-c.inc" |
| 222 |
|
|
|
| 223 |
|
|
MODULE = Socket PACKAGE = Socket |
| 224 |
|
|
|
| 225 |
|
|
INCLUDE: const-xs.inc |
| 226 |
|
|
|
| 227 |
|
|
void |
| 228 |
|
|
inet_aton(host) |
| 229 |
|
|
char * host |
| 230 |
|
|
CODE: |
| 231 |
|
|
{ |
| 232 |
|
|
struct in_addr ip_address; |
| 233 |
|
|
struct hostent * phe; |
| 234 |
|
|
int ok = |
| 235 |
|
|
(host != NULL) && |
| 236 |
|
|
(*host != '\0') && |
| 237 |
|
|
inet_aton(host, &ip_address); |
| 238 |
|
|
|
| 239 |
|
|
if (!ok && (phe = gethostbyname(host))) { |
| 240 |
|
|
Copy( phe->h_addr, &ip_address, phe->h_length, char ); |
| 241 |
|
|
ok = 1; |
| 242 |
|
|
} |
| 243 |
|
|
|
| 244 |
|
|
ST(0) = sv_newmortal(); |
| 245 |
|
|
if (ok) |
| 246 |
|
|
sv_setpvn( ST(0), (char *)&ip_address, sizeof ip_address ); |
| 247 |
|
|
} |
| 248 |
|
|
|
| 249 |
|
|
void |
| 250 |
|
|
inet_ntoa(ip_address_sv) |
| 251 |
|
|
SV * ip_address_sv |
| 252 |
|
|
CODE: |
| 253 |
|
|
{ |
| 254 |
|
|
STRLEN addrlen; |
| 255 |
|
|
struct in_addr addr; |
| 256 |
|
|
char * addr_str; |
| 257 |
|
|
char * ip_address; |
| 258 |
|
|
if (DO_UTF8(ip_address_sv) && !sv_utf8_downgrade(ip_address_sv, 1)) |
| 259 |
|
|
croak("Wide character in Socket::inet_ntoa"); |
| 260 |
|
|
ip_address = SvPVbyte(ip_address_sv, addrlen); |
| 261 |
|
|
if (addrlen == sizeof(addr) || addrlen == 4) |
| 262 |
|
|
addr.s_addr = |
| 263 |
|
|
(ip_address[0] & 0xFF) << 24 | |
| 264 |
|
|
(ip_address[1] & 0xFF) << 16 | |
| 265 |
|
|
(ip_address[2] & 0xFF) << 8 | |
| 266 |
|
|
(ip_address[3] & 0xFF); |
| 267 |
|
|
else |
| 268 |
|
|
croak("Bad arg length for %s, length is %d, should be %d", |
| 269 |
|
|
"Socket::inet_ntoa", |
| 270 |
|
|
addrlen, sizeof(addr)); |
| 271 |
|
|
/* We could use inet_ntoa() but that is broken |
| 272 |
|
|
* in HP-UX + GCC + 64bitint (returns "0.0.0.0"), |
| 273 |
|
|
* so let's use this sprintf() workaround everywhere. |
| 274 |
|
|
* This is also more threadsafe than using inet_ntoa(). */ |
| 275 |
|
|
New(1138, addr_str, 4 * 3 + 3 + 1, char); /* IPv6? */ |
| 276 |
|
|
sprintf(addr_str, "%d.%d.%d.%d", |
| 277 |
|
|
((addr.s_addr >> 24) & 0xFF), |
| 278 |
|
|
((addr.s_addr >> 16) & 0xFF), |
| 279 |
|
|
((addr.s_addr >> 8) & 0xFF), |
| 280 |
|
|
( addr.s_addr & 0xFF)); |
| 281 |
|
|
ST(0) = sv_2mortal(newSVpvn(addr_str, strlen(addr_str))); |
| 282 |
|
|
Safefree(addr_str); |
| 283 |
|
|
} |
| 284 |
|
|
|
| 285 |
|
|
void |
| 286 |
|
|
sockaddr_family(sockaddr) |
| 287 |
|
|
SV * sockaddr |
| 288 |
|
|
PREINIT: |
| 289 |
|
|
STRLEN sockaddr_len; |
| 290 |
|
|
char *sockaddr_pv = SvPVbyte(sockaddr, sockaddr_len); |
| 291 |
|
|
CODE: |
| 292 |
|
|
if (sockaddr_len < offsetof(struct sockaddr, sa_data)) { |
| 293 |
|
|
croak("Bad arg length for %s, length is %d, should be at least %d", |
| 294 |
|
|
"Socket::sockaddr_family", sockaddr_len, |
| 295 |
|
|
offsetof(struct sockaddr, sa_data)); |
| 296 |
|
|
} |
| 297 |
|
|
ST(0) = sv_2mortal(newSViv(((struct sockaddr*)sockaddr_pv)->sa_family)); |
| 298 |
|
|
|
| 299 |
|
|
void |
| 300 |
|
|
pack_sockaddr_un(pathname) |
| 301 |
|
|
SV * pathname |
| 302 |
|
|
CODE: |
| 303 |
|
|
{ |
| 304 |
|
|
#ifdef I_SYS_UN |
| 305 |
|
|
struct sockaddr_un sun_ad; /* fear using sun */ |
| 306 |
|
|
STRLEN len; |
| 307 |
|
|
char * pathname_pv; |
| 308 |
|
|
|
| 309 |
|
|
Zero( &sun_ad, sizeof sun_ad, char ); |
| 310 |
|
|
sun_ad.sun_family = AF_UNIX; |
| 311 |
|
|
pathname_pv = SvPV(pathname,len); |
| 312 |
|
|
if (len > sizeof(sun_ad.sun_path)) |
| 313 |
|
|
len = sizeof(sun_ad.sun_path); |
| 314 |
|
|
# ifdef OS2 /* Name should start with \socket\ and contain backslashes! */ |
| 315 |
|
|
{ |
| 316 |
|
|
int off; |
| 317 |
|
|
char *s, *e; |
| 318 |
|
|
|
| 319 |
|
|
if (pathname_pv[0] != '/' && pathname_pv[0] != '\\') |
| 320 |
|
|
croak("Relative UNIX domain socket name '%s' unsupported", |
| 321 |
|
|
pathname_pv); |
| 322 |
|
|
else if (len < 8 |
| 323 |
|
|
|| pathname_pv[7] != '/' && pathname_pv[7] != '\\' |
| 324 |
|
|
|| !strnicmp(pathname_pv + 1, "socket", 6)) |
| 325 |
|
|
off = 7; |
| 326 |
|
|
else |
| 327 |
|
|
off = 0; /* Preserve names starting with \socket\ */ |
| 328 |
|
|
Copy( "\\socket", sun_ad.sun_path, off, char); |
| 329 |
|
|
Copy( pathname_pv, sun_ad.sun_path + off, len, char ); |
| 330 |
|
|
|
| 331 |
|
|
s = sun_ad.sun_path + off - 1; |
| 332 |
|
|
e = s + len + 1; |
| 333 |
|
|
while (++s < e) |
| 334 |
|
|
if (*s = '/') |
| 335 |
|
|
*s = '\\'; |
| 336 |
|
|
} |
| 337 |
|
|
# else /* !( defined OS2 ) */ |
| 338 |
|
|
Copy( pathname_pv, sun_ad.sun_path, len, char ); |
| 339 |
|
|
# endif |
| 340 |
|
|
if (0) not_here("dummy"); |
| 341 |
|
|
ST(0) = sv_2mortal(newSVpvn((char *)&sun_ad, sizeof sun_ad)); |
| 342 |
|
|
#else |
| 343 |
|
|
ST(0) = (SV *) not_here("pack_sockaddr_un"); |
| 344 |
|
|
#endif |
| 345 |
|
|
|
| 346 |
|
|
} |
| 347 |
|
|
|
| 348 |
|
|
void |
| 349 |
|
|
unpack_sockaddr_un(sun_sv) |
| 350 |
|
|
SV * sun_sv |
| 351 |
|
|
CODE: |
| 352 |
|
|
{ |
| 353 |
|
|
#ifdef I_SYS_UN |
| 354 |
|
|
struct sockaddr_un addr; |
| 355 |
|
|
STRLEN sockaddrlen; |
| 356 |
|
|
char * sun_ad = SvPVbyte(sun_sv,sockaddrlen); |
| 357 |
|
|
char * e; |
| 358 |
|
|
# ifndef __linux__ |
| 359 |
|
|
/* On Linux sockaddrlen on sockets returned by accept, recvfrom, |
| 360 |
|
|
getpeername and getsockname is not equal to sizeof(addr). */ |
| 361 |
|
|
if (sockaddrlen != sizeof(addr)) { |
| 362 |
|
|
croak("Bad arg length for %s, length is %d, should be %d", |
| 363 |
|
|
"Socket::unpack_sockaddr_un", |
| 364 |
|
|
sockaddrlen, sizeof(addr)); |
| 365 |
|
|
} |
| 366 |
|
|
# endif |
| 367 |
|
|
|
| 368 |
|
|
Copy( sun_ad, &addr, sizeof addr, char ); |
| 369 |
|
|
|
| 370 |
|
|
if ( addr.sun_family != AF_UNIX ) { |
| 371 |
|
|
croak("Bad address family for %s, got %d, should be %d", |
| 372 |
|
|
"Socket::unpack_sockaddr_un", |
| 373 |
|
|
addr.sun_family, |
| 374 |
|
|
AF_UNIX); |
| 375 |
|
|
} |
| 376 |
|
|
e = (char*)addr.sun_path; |
| 377 |
|
|
/* On Linux, the name of abstract unix domain sockets begins |
| 378 |
|
|
* with a '\0', so allow this. */ |
| 379 |
|
|
while ((*e || (e == addr.sun_path && e[1] && sockaddrlen > 1)) |
| 380 |
|
|
&& e < (char*)addr.sun_path + sizeof addr.sun_path) |
| 381 |
|
|
++e; |
| 382 |
|
|
ST(0) = sv_2mortal(newSVpvn(addr.sun_path, e - (char*)addr.sun_path)); |
| 383 |
|
|
#else |
| 384 |
|
|
ST(0) = (SV *) not_here("unpack_sockaddr_un"); |
| 385 |
|
|
#endif |
| 386 |
|
|
} |
| 387 |
|
|
|
| 388 |
|
|
void |
| 389 |
|
|
pack_sockaddr_in(port, ip_address_sv) |
| 390 |
|
|
unsigned short port |
| 391 |
|
|
SV * ip_address_sv |
| 392 |
|
|
CODE: |
| 393 |
|
|
{ |
| 394 |
|
|
struct sockaddr_in sin; |
| 395 |
|
|
struct in_addr addr; |
| 396 |
|
|
STRLEN addrlen; |
| 397 |
|
|
char * ip_address; |
| 398 |
|
|
if (DO_UTF8(ip_address_sv) && !sv_utf8_downgrade(ip_address_sv, 1)) |
| 399 |
|
|
croak("Wide character in Socket::pack_sockaddr_in"); |
| 400 |
|
|
ip_address = SvPVbyte(ip_address_sv, addrlen); |
| 401 |
|
|
if (addrlen == sizeof(addr) || addrlen == 4) |
| 402 |
|
|
addr.s_addr = |
| 403 |
|
|
(ip_address[0] & 0xFF) << 24 | |
| 404 |
|
|
(ip_address[1] & 0xFF) << 16 | |
| 405 |
|
|
(ip_address[2] & 0xFF) << 8 | |
| 406 |
|
|
(ip_address[3] & 0xFF); |
| 407 |
|
|
else |
| 408 |
|
|
croak("Bad arg length for %s, length is %d, should be %d", |
| 409 |
|
|
"Socket::pack_sockaddr_in", |
| 410 |
|
|
addrlen, sizeof(addr)); |
| 411 |
|
|
Zero( &sin, sizeof sin, char ); |
| 412 |
|
|
sin.sin_family = AF_INET; |
| 413 |
|
|
sin.sin_port = htons(port); |
| 414 |
|
|
sin.sin_addr.s_addr = htonl(addr.s_addr); |
| 415 |
|
|
ST(0) = sv_2mortal(newSVpvn((char *)&sin, sizeof sin)); |
| 416 |
|
|
} |
| 417 |
|
|
|
| 418 |
|
|
void |
| 419 |
|
|
unpack_sockaddr_in(sin_sv) |
| 420 |
|
|
SV * sin_sv |
| 421 |
|
|
PPCODE: |
| 422 |
|
|
{ |
| 423 |
|
|
STRLEN sockaddrlen; |
| 424 |
|
|
struct sockaddr_in addr; |
| 425 |
|
|
unsigned short port; |
| 426 |
|
|
struct in_addr ip_address; |
| 427 |
|
|
char * sin = SvPVbyte(sin_sv,sockaddrlen); |
| 428 |
|
|
if (sockaddrlen != sizeof(addr)) { |
| 429 |
|
|
croak("Bad arg length for %s, length is %d, should be %d", |
| 430 |
|
|
"Socket::unpack_sockaddr_in", |
| 431 |
|
|
sockaddrlen, sizeof(addr)); |
| 432 |
|
|
} |
| 433 |
|
|
Copy( sin, &addr,sizeof addr, char ); |
| 434 |
|
|
if ( addr.sin_family != AF_INET ) { |
| 435 |
|
|
croak("Bad address family for %s, got %d, should be %d", |
| 436 |
|
|
"Socket::unpack_sockaddr_in", |
| 437 |
|
|
addr.sin_family, |
| 438 |
|
|
AF_INET); |
| 439 |
|
|
} |
| 440 |
|
|
port = ntohs(addr.sin_port); |
| 441 |
|
|
ip_address = addr.sin_addr; |
| 442 |
|
|
|
| 443 |
|
|
EXTEND(SP, 2); |
| 444 |
|
|
PUSHs(sv_2mortal(newSViv((IV) port))); |
| 445 |
|
|
PUSHs(sv_2mortal(newSVpvn((char *)&ip_address, sizeof ip_address))); |
| 446 |
|
|
} |