| 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 | Newx(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 | }
|
|---|