Newer
Older
NetAddr-IP / Lite / Util / Util.xs
@Michael Robinton Michael Robinton on 21 Oct 2014 16 KB Import of MIKER/NetAddr-IP-4.028 from CPAN.
  1.  
  2. /*
  3. * Copyright 2006 - 2010, Michael Robinton <michael@bizsystems.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19.  
  20. #ifdef __cplusplus
  21. extern "C" {
  22. #endif
  23.  
  24. #ifdef _CYGWIN
  25. #include <windows.h>
  26. #endif
  27.  
  28. #include "EXTERN.h"
  29. #include "perl.h"
  30. #include "XSUB.h"
  31.  
  32. /* needed for testing with 'printf'
  33. #include <stdio.h>
  34. */
  35.  
  36. #ifdef _CYGWIN
  37. #include <Win32-Extensions.h>
  38. #endif
  39.  
  40. #include "localconf.h"
  41.  
  42. #ifdef __cplusplus
  43. }
  44. #endif
  45.  
  46. /* workaround for OS's without inet_aton */
  47. #include "xs_include/inet_aton.c"
  48.  
  49. typedef union
  50. {
  51. u_int32_t u[4];
  52. unsigned char c[16];
  53. } n128;
  54.  
  55. char * is_ipv6to4 = "ipv6to4", * is_shiftleft = "shiftleft", * is_comp128 = "comp128";
  56. char * is_sub128 = "sub128", * is_add128 = "add128";
  57. char * is_hasbits = "hasbits", * is_isIPv4 = "isIPv4";
  58. char * is_bcd2bin = "bcd2bin", * is_simple_pack = "simple_pack", * is_bcdn2bin = "bcdn2bin";
  59. char * is_mask4to6 = "mask4to6", * is_ipv4to6 = "ipv4to6";
  60. char * is_maskanyto6 = "maskanyto6", * is_ipanyto6 = "ipanyto6";
  61.  
  62. typedef struct bcdstuff
  63. { /* character array of 40 bytes */
  64. char txt[21]; /* 20 bytes + string terminator */
  65. u_int32_t bcd[5]; /* 20 bytes, 40 digits */
  66. } BCD;
  67.  
  68. #define zero ('0' & 0x7f)
  69.  
  70. /* useful for debug, prints the 128 bits of 8, 16 bit registers */
  71. void
  72. printb128(char * b)
  73. {
  74. int c;
  75. for(c=0;c<16;c++) {
  76. if (b[c] &0x80)
  77. printf("1");
  78. else
  79. printf("0");
  80. if (b[c] &0x40)
  81. printf("1");
  82. else
  83. printf("0");
  84. if (b[c] &0x20)
  85. printf("1");
  86. else
  87. printf("0");
  88. if (b[c] &0x10)
  89. printf("1");
  90. else
  91. printf("0");
  92. if (b[c] &0x8)
  93. printf("1");
  94. else
  95. printf("0");
  96. if (b[c] &0x4)
  97. printf("1");
  98. else
  99. printf("0");
  100. if (b[c] &0x2)
  101. printf("1");
  102. else
  103. printf("0");
  104. if (b[c] &0x1)
  105. printf("1");
  106. else
  107. printf("0");
  108. if (c == 3 || c == 7 || c == 11)
  109. printf("\n");
  110. }
  111. printf("\n\n");
  112. }
  113.  
  114. void
  115. extendipv4(void * aa, void * ux)
  116. {
  117. register u_int32_t * a = ux;
  118. *a++ = 0;
  119. *a++ = 0;
  120. *a++ = 0;
  121. *a = *((u_int32_t *)aa);
  122. }
  123.  
  124. void
  125. extendmask4(void * aa, void * ux)
  126. {
  127. register u_int32_t * a = ux;
  128. *a++ = 0xffffffff;
  129. *a++ = 0xffffffff;
  130. *a++ = 0xffffffff;
  131. *a = *((u_int32_t *)aa);
  132. }
  133.  
  134. void
  135. fastcomp128(void * aa)
  136. {
  137. register u_int32_t * a = aa;
  138.  
  139. *a++ ^= 0xffffffff;
  140. *a++ ^= 0xffffffff;
  141. *a++ ^= 0xffffffff;
  142. *a++ ^= 0xffffffff;
  143. }
  144.  
  145. /* add two 128 bit numbers
  146. return the carry
  147. */
  148.  
  149. int
  150. adder128(void * aa, void * bb, n128 * ap128, int carry)
  151. {
  152. int i;
  153. register u_int32_t a, b, r;
  154.  
  155. for (i=3; i >= 0; i--) {
  156. a = *((u_int32_t *)aa + i);
  157. b = *((u_int32_t *)bb + i);
  158. r = a + b;
  159. a = 0; /* ripple carry forward */
  160. if ( r < a || r < b) /* if overflow */
  161. a = 1;
  162.  
  163. b = r + carry; /* carry propagate in */
  164. if (b < r) /* ripple carry forward */
  165. carry = 1; /* if overflow */
  166. else
  167. carry = a;
  168.  
  169. *((u_int32_t *)(ap128->u) + i) = b;
  170. }
  171. return carry;
  172. }
  173.  
  174. int
  175. addercon(void * aa, u_int32_t * bb, n128 * ap128, int32_t con)
  176. {
  177. register u_int32_t tmp = 0x80000000;
  178.  
  179. if (con & tmp)
  180. tmp = 0xffffffff;
  181. else
  182. tmp = 0;
  183.  
  184. bb[0] = tmp;
  185. bb[1] = tmp;
  186. bb[2] = tmp;
  187. bb[3] = (u_int32_t)con;
  188. return adder128(aa,bb,ap128,0);
  189. }
  190.  
  191. int
  192. have128(void * bp)
  193. {
  194. register u_int32_t * p = bp;
  195.  
  196. if (*p++ || *p++ || *p++ || *p++)
  197. return 1;
  198. return 0;
  199. }
  200.  
  201. int
  202. _isipv4(void * bp)
  203. {
  204. register u_int32_t * p = bp;
  205.  
  206. if (*p++ || *p++ || *p++)
  207. return 0;
  208. return 1;
  209. }
  210.  
  211. /* network byte swap and copy */
  212. void
  213. netswap_copy(void * dest, void * src, int len)
  214. {
  215. register u_int32_t * d = dest, * s = src;
  216.  
  217. for (/* -- */;len>0;len--) {
  218. #ifdef host_is_LITTLE_ENDIAN
  219. *d++ = (((*s & 0xff000000) >> 24) | ((*s & 0x00ff0000) >> 8) | \
  220. ((*s & 0x0000ff00) << 8) | ((*s & 0x000000ff) << 24));
  221. #else
  222. # ifdef host_is_BIG_ENDIAN
  223. *d++ = *s;
  224. # else
  225. # error ENDIANness not defined
  226. # endif
  227. #endif
  228. s++;
  229. }
  230. }
  231.  
  232. /* do ntohl / htonl changes as necessary for this OS
  233. */
  234. void
  235. netswap(void * ap, int len)
  236. {
  237. #ifdef host_is_LITTLE_ENDIAN
  238. register u_int32_t * a = ap;
  239. for (/* -- */;len >0;len--) {
  240. *a = (((*a & 0xff000000) >> 24) | ((*a & 0x00ff0000) >> 8) | \
  241. ((*a & 0x0000ff00) << 8) | ((*a & 0x000000ff) << 24));
  242. a++;
  243. }
  244. #endif
  245. }
  246.  
  247. /* shift right to purge '0's,
  248. return mask bit count and remainder value,
  249. left fill with ones
  250. */
  251. unsigned char
  252. _countbits(void *ap)
  253. {
  254. register u_int32_t * p0 = (u_int32_t *)ap, * p1 = p0 +1, * p2 = p1 +1, * p3 = p2 +1;
  255. unsigned char count = 128;
  256.  
  257. fastcomp128(ap);
  258.  
  259. do {
  260. if (!(*p3 & 1))
  261. break;
  262. count--;
  263. *p3 >>= 1;
  264. if (*p2 & 1)
  265. *p3 |= 0x80000000;
  266. *p2 >>= 1;
  267. if (*p1 & 1)
  268. *p2 |= 0x80000000;
  269. *p1 >>= 1;
  270. if (*p0 & 1)
  271. *p1 |= 0x80000000;
  272. *p0 >>= 1;
  273. } while (count > 0);
  274. return count;
  275. }
  276.  
  277. /* multiply 128 bit number x 2
  278. */
  279. void
  280. _128x2(u_int32_t * ap)
  281. {
  282. register u_int32_t * p = ap +3, tmpc, carry = 0;
  283.  
  284. do {
  285. tmpc = *p & 0x80000000; /* propagate hi bit to next word */
  286. *p <<= 1;
  287. if (carry)
  288. *p += 1;
  289. carry = tmpc;
  290. } while (p-- > ap);
  291. /* printf("2o %04X:%04X:%04X:%04X\n",*(ap),*(ap +1),*(ap +2),*(ap +3)); */
  292. }
  293.  
  294. /* multiply 128 bit number X10
  295. */
  296. void
  297. _128x10(n128 * ap128, n128 * tp128)
  298. {
  299. register u_int32_t * ap = ap128->u, * tp = tp128->u;
  300. _128x2(ap); /* multiply by two */
  301. *tp = *ap; /* temp save */
  302. *(tp +1) = *(ap +1);
  303. *(tp +2) = *(ap +2);
  304. *(tp +3) = *(ap +3);
  305. _128x2(ap);
  306. _128x2(ap); /* times 8 */
  307. (void) adder128(ap,tp,ap128,0);
  308. /* printf("x %04X:%04X:%04X:%04X\n",*((u_int32_t *)ap),*((u_int32_t *)ap +1),*((u_int32_t *)ap +2),*((u_int32_t *)ap +3)); */
  309. }
  310.  
  311. /* multiply 128 bit number by 10, add bcd digit to result
  312. */
  313. void
  314. _128x10plusbcd(n128 * ap128, n128 * tp128, char digit)
  315. {
  316. register u_int32_t * ap = ap128->u, * tp = tp128->u;
  317. /* printf("digit %X + %X = ",digit,*(ap +3)); */
  318. _128x10(ap128,tp128);
  319. *tp = 0;
  320. *(tp + 1) = 0;
  321. *(tp + 2) = 0;
  322. *(tp + 3) = digit;
  323. (void) adder128(ap,tp,ap128,0);
  324. /* printf("%d %04X:%04X:%04X:%04X\n",digit,*((u_int32_t *)ap),*((u_int32_t *)ap +1),*((u_int32_t *)ap +2),*((u_int32_t *)ap +3)); */
  325. }
  326.  
  327. char
  328. _simple_pack(void * str,int len, BCD * n)
  329. {
  330. int i = len -1, j=19, lo=1;
  331. register unsigned char c, * bcdn = (unsigned char *)(n->bcd), * sp = (unsigned char *) str;
  332.  
  333. if (len > 40)
  334. return '*'; /* error, input string too long */
  335.  
  336. memset (bcdn, 0, 20);
  337.  
  338. do {
  339. c = *(sp + i) & 0x7f;
  340. if (c < zero || c > (zero + 9))
  341. return c; /* error, out of range */
  342.  
  343. if (lo) { /* lo byte ? */
  344. *(bcdn + j) = c & 0xF;
  345. lo = 0;
  346. }
  347. else {
  348. c <<= 4;
  349. *(bcdn + j) |= c;
  350. lo = 1; /* lo byte next */
  351. j--;
  352. }
  353. } while (i-- > 0);
  354. return 0;
  355. }
  356.  
  357. /* convert a packed bcd string to 128 bit binary string
  358. */
  359. void
  360. _bcdn2bin(void * bp, n128 * ap128, n128 * cp128, int len)
  361. {
  362. int i = 0, hasdigits = 0, lo;
  363. register unsigned char c, * cp = (unsigned char *)bp;
  364.  
  365. memset(ap128->c, 0, 16);
  366. memset(cp128->c, 0, 16);
  367.  
  368. while (i < len ) {
  369. c = *cp++;
  370. for (lo=0;lo<2;lo+=1) {
  371. if (lo) {
  372. if (hasdigits) /* suppress leading zero multiplications */
  373. _128x10plusbcd(ap128, cp128, c & 0xF);
  374. else {
  375. if (c & 0xF) {
  376. hasdigits = 1;
  377. ap128->u[3] = c & 0xF;
  378. }
  379. }
  380. }
  381. else {
  382. if (hasdigits) /* suppress leading zero multiplications */
  383. _128x10plusbcd(ap128, cp128, c >> 4);
  384. else {
  385. if (c & 0XF0) {
  386. hasdigits = 1;
  387. ap128->u[3] = c >> 4;
  388. }
  389. }
  390. }
  391. i++;
  392. if (i >= len)
  393. break;
  394. }
  395. }
  396. }
  397.  
  398. /* convert a 128 bit number string to a bcd number string
  399. returns the length of the bcd string === 20
  400. */
  401. int
  402. _bin2bcd (unsigned char * binary, BCD * n)
  403. {
  404. register u_int32_t tmp, add3, msk8, bcd8, carry = 0;
  405. u_int32_t word;
  406. unsigned char binmsk = 0;
  407. int c = 0,i, j, p;
  408.  
  409. memset (n->bcd, 0, 20);
  410.  
  411. for (p=0;p<128;p++) { /* bit pointer */
  412. if (! binmsk) {
  413. word = *((unsigned char *)binary + c);
  414. binmsk = 0x80;
  415. c++;
  416. }
  417. carry = word & binmsk; /* bit to convert */
  418. binmsk >>= 1;
  419. for (i=4;i>=0;i--) {
  420. bcd8 = n->bcd[i];
  421. if (carry | bcd8) { /* if something to do */
  422. add3 = 3;
  423. msk8 = 8;
  424.  
  425. for (j=0;j<8;j++) { /* prep bcd digits for X2 */
  426. tmp = bcd8 + add3;
  427. if (tmp & msk8)
  428. bcd8 = tmp;
  429. add3 <<= 4;
  430. msk8 <<= 4;
  431. }
  432. tmp = bcd8 & 0x80000000; /* propagated carry */
  433. bcd8 <<= 1; /* x 2 */
  434. if (carry)
  435. bcd8 += 1;
  436. n->bcd[i] = bcd8;
  437. carry = tmp;
  438. }
  439. }
  440. }
  441. netswap(n->bcd,5);
  442. return 20;
  443. }
  444.  
  445. /* convert a bcd number string to a bcd text string
  446. returns the number of digits
  447. */
  448. int
  449. _bcd2txt(unsigned char * bcd2p, BCD * n)
  450. {
  451. register unsigned char bcd, dchar;
  452. int i, j = 0;
  453.  
  454. for (i=0;i<20;i++) {
  455. dchar = *(bcd2p + i);
  456. bcd = dchar >> 4;
  457. if (j || bcd) {
  458. n->txt[j] = bcd + zero;
  459. j++;
  460. }
  461. bcd = dchar & 0xF;
  462. if (j || bcd || i == 19) { /* must be at least one digit */
  463. n->txt[j] = bcd + zero;
  464. j++;
  465. }
  466. }
  467. n->txt[j] = 0; /* string terminator */
  468. return j;
  469. }
  470.  
  471. MODULE = NetAddr::IP::Util PACKAGE = NetAddr::IP::Util
  472.  
  473. PROTOTYPES: ENABLE
  474.  
  475. INCLUDE: xs_include/miniSocket.inc
  476.  
  477. void
  478. comp128(s,...)
  479. SV * s
  480. ALIAS:
  481. NetAddr::IP::Util::ipv6to4 = 2
  482. NetAddr::IP::Util::shiftleft = 1
  483. PREINIT:
  484. unsigned char * ap;
  485. char * subname;
  486. u_int32_t wa[4];
  487. STRLEN len;
  488. int i;
  489. PPCODE:
  490. ap = (unsigned char *) SvPV(s,len);
  491. if (len != 16) {
  492. if (ix == 2)
  493. subname = is_ipv6to4;
  494. else if (ix == 1)
  495. subname = is_shiftleft;
  496. else
  497. subname = is_comp128;
  498. croak("Bad arg length for %s%s, length is %d, should be %d",
  499. "NetAddr::IP::Util::",subname,len *8,128);
  500. }
  501. if (ix == 2) {
  502. XPUSHs(sv_2mortal(newSVpvn((char *)(ap +12),4)));
  503. XSRETURN(1);
  504. }
  505. else if (ix == 1) {
  506. if (items < 2) {
  507. memcpy(wa,ap,16);
  508. }
  509. else if ((i = SvIV(ST(1))) == 0) {
  510. memcpy(wa,ap,16);
  511. }
  512. else if (i < 0 || i > 128) {
  513. croak("Bad arg value for %s, is %d, should be 0 thru 128",
  514. "NetAddr::IP::Util::shiftleft",i);
  515. }
  516. else {
  517. netswap_copy(wa,ap,4);
  518. do {
  519. _128x2(wa);
  520. i--;
  521. } while (i > 0);
  522. netswap(wa,4);
  523. }
  524. }
  525. else {
  526. memcpy(wa,ap,16);
  527. fastcomp128(wa);
  528. }
  529. XPUSHs(sv_2mortal(newSVpvn((char *)wa,16)));
  530. XSRETURN(1);
  531.  
  532. void
  533. add128(as,bs)
  534. SV * as
  535. SV * bs
  536. ALIAS:
  537. NetAddr::IP::Util::sub128 = 1
  538. PREINIT:
  539. unsigned char * ap, *bp;
  540. char * subname;
  541. u_int32_t wa[4], wb[4];
  542. n128 a128;
  543. STRLEN len;
  544. PPCODE:
  545. ap = (unsigned char *) SvPV(as,len);
  546. if (len != 16) {
  547. Bail:
  548. if (ix == 1)
  549. subname = is_sub128;
  550. else
  551. subname = is_add128;
  552. croak("Bad arg length for %s%s, length is %d, should be %d",
  553. "NetAddr::IP::Util::",subname,len *8,128);
  554. }
  555.  
  556. bp = (unsigned char *) SvPV(bs,len);
  557. if (len != 16) {
  558. goto Bail;
  559. }
  560. netswap_copy(wa,ap,4);
  561. netswap_copy(wb,bp,4);
  562. if (ix == 1) {
  563. fastcomp128(wb);
  564. XPUSHs(sv_2mortal(newSViv((I32)adder128(wa,wb,&a128,1))));
  565. }
  566. else {
  567. XPUSHs(sv_2mortal(newSViv((I32)adder128(wa,wb,&a128,0))));
  568. }
  569. if (GIMME_V == G_ARRAY) {
  570. netswap(a128.u,4);
  571. XPUSHs(sv_2mortal(newSVpvn((char *)a128.c,16)));
  572. XSRETURN(2);
  573. }
  574. XSRETURN(1);
  575.  
  576. void
  577. addconst(s,cnst)
  578. SV * s
  579. I32 cnst
  580. PREINIT:
  581. n128 a128;
  582. unsigned char * ap;
  583. u_int32_t wa[4], wb[4];
  584. STRLEN len;
  585. PPCODE:
  586. ap = (unsigned char *) SvPV(s,len);
  587. if (len != 16) {
  588. croak("Bad arg length for %s, length is %d, should be %d",
  589. "NetAddr::IP::Util::addconst",len *8,128);
  590. }
  591. netswap_copy(wa,ap,4);
  592. XPUSHs(sv_2mortal(newSViv((I32)addercon(wa,wb,&a128,cnst))));
  593. if (GIMME_V == G_ARRAY) {
  594. netswap(a128.u,4);
  595. XPUSHs(sv_2mortal(newSVpvn((char *)a128.c,16)));
  596. XSRETURN(2);
  597. }
  598. XSRETURN(1);
  599.  
  600.  
  601. int
  602. hasbits(s)
  603. SV * s
  604. ALIAS:
  605. NetAddr::IP::Util::isIPv4 = 1
  606. PREINIT:
  607. unsigned char * bp;
  608. char * subname;
  609. STRLEN len;
  610. CODE:
  611. bp = (unsigned char *) SvPV(s,len);
  612. if (len != 16) {
  613. if (ix == 1)
  614. subname = is_isIPv4;
  615. else
  616. subname = is_hasbits;
  617. croak("Bad arg length for %s%s, length is %d, should be %d",
  618. "NetAddr::IP::Util::",subname,len *8,128);
  619. }
  620. if (ix == 1) {
  621. RETVAL = _isipv4(bp);
  622. }
  623. else {
  624. RETVAL = have128(bp);
  625. }
  626. OUTPUT:
  627. RETVAL
  628.  
  629. void
  630. bin2bcd(s)
  631. SV * s
  632. ALIAS:
  633. NetAddr::IP::Util::bcdn2txt = 2
  634. NetAddr::IP::Util::bin2bcdn = 1
  635. PREINIT:
  636. BCD n;
  637. unsigned char * cp;
  638. STRLEN len;
  639. PPCODE:
  640. cp = (unsigned char *) SvPV(s,len);
  641. if (ix == 0) {
  642. if (len != 16) {
  643. croak("Bad arg length for %s, length is %d, should be %d",
  644. "NetAddr::IP::Util::bin2bcd",len *8,128);
  645. }
  646. (void) _bin2bcd(cp,&n);
  647. XPUSHs(sv_2mortal(newSVpvn((char *)n.txt,_bcd2txt((unsigned char *)n.bcd,&n))));
  648. }
  649. else if (ix == 1) {
  650. if (len != 16) {
  651. croak("Bad arg length for %s, length is %d, should be %d",
  652. "NetAddr::IP::Util::bin2bcdn",len *8,128);
  653. }
  654. XPUSHs(sv_2mortal(newSVpvn((char *)n.bcd,_bin2bcd(cp,&n))));
  655. }
  656. else {
  657. if (len > 20) {
  658. croak("Bad arg length for %s, length is %d, should %d digits or less",
  659. "NetAddr::IP::Util::bcdn2txt",len *2,40);
  660. }
  661. XPUSHs(sv_2mortal(newSVpvn((char *)n.txt,_bcd2txt(cp,&n))));
  662. }
  663. XSRETURN(1);
  664.  
  665. #*
  666. #* the second argument 'len' is the number of bcd digits for
  667. #* the bcdn2bin conversion. Pack looses track of the number
  668. #* digits so this is needed to do the "right thing".
  669. #* NOTE: that simple_pack always returns 40 digits
  670. #*
  671. void
  672. bcd2bin(s,...)
  673. SV * s
  674. ALIAS:
  675. NetAddr::IP::Util::bcdn2bin = 2
  676. NetAddr::IP::Util::simple_pack = 1
  677. PREINIT:
  678. BCD n;
  679. n128 c128, a128;
  680. unsigned char * cp, badc;
  681. char * subname;
  682. STRLEN len;
  683. PPCODE:
  684. cp = (unsigned char *) SvPV(s,len);
  685. if (len > 40) {
  686. if (ix == 0)
  687. subname = is_bcd2bin;
  688. else if (ix ==1)
  689. subname = is_simple_pack;
  690. Badigits:
  691. croak("Bad arg length for %s%s, length is %d, should be %d digits or less",
  692. "NetAddr::IP::Util::",subname,len,40);
  693. }
  694. if (ix == 2) {
  695. if (len > 20) {
  696. len <<= 1; /* times 2 */
  697. subname = is_bcdn2bin;
  698. goto Badigits;
  699. }
  700. if (items < 2) {
  701. croak("Bad usage, should have %s('packedbcd,length)",
  702. "NetAddr::IP::Util::bcdn2bin");
  703. }
  704. len = SvIV(ST(1));
  705. _bcdn2bin(cp,&a128,&c128,(int)len);
  706. netswap(a128.u,4);
  707. XPUSHs(sv_2mortal(newSVpvn((char *)a128.c,16)));
  708. XSRETURN(1);
  709. }
  710. badc = _simple_pack(cp,(int)len, &n);
  711. if (badc) {
  712. if (ix == 1)
  713. subname = is_simple_pack;
  714. else
  715. subname = is_bcd2bin;
  716. croak("Bad char in string for %s%s, character is '%c', allowed are 0-9",
  717. "NetAddr::IP::Util::",subname,badc);
  718. }
  719. if (ix == 0) {
  720. _bcdn2bin((void *)n.bcd,&a128,&c128,40);
  721. netswap(a128.u,4);
  722. XPUSHs(sv_2mortal(newSVpvn((char *)a128.c,16)));
  723. }
  724. else { /* ix == 1 */
  725. XPUSHs(sv_2mortal(newSVpvn((char *)n.bcd,20)));
  726. }
  727. XSRETURN(1);
  728.  
  729. void
  730. notcontiguous(s)
  731. SV * s
  732. PREINIT:
  733. unsigned char * ap, count;
  734. u_int32_t wa[4];
  735. STRLEN len;
  736. PPCODE:
  737. ap = (unsigned char *) SvPV(s,len);
  738. if (len != 16) {
  739. croak("Bad arg length for %s, length is %d, should be %d",
  740. "NetAddr::IP::Util::countbits",len *8,128);
  741. }
  742. netswap_copy(wa,ap,4);
  743. count = _countbits(wa);
  744. XPUSHs(sv_2mortal(newSViv((I32)have128(wa))));
  745. if (GIMME_V == G_ARRAY) {
  746. XPUSHs(sv_2mortal(newSViv((I32)count)));
  747. XSRETURN(2);
  748. }
  749. XSRETURN(1);
  750.  
  751. void
  752. ipv4to6(s)
  753. SV * s
  754. ALIAS:
  755. NetAddr::IP::Util::mask4to6 = 1
  756. PREINIT:
  757. unsigned char * ip;
  758. char * subname;
  759. u_int32_t wa[4];
  760. STRLEN len;
  761. PPCODE:
  762. ip = (unsigned char *) SvPV(s,len);
  763. if (len != 4) {
  764. if (ix == 1)
  765. subname = is_mask4to6;
  766. else
  767. subname = is_ipv4to6;
  768. croak("Bad arg length for %s%s, length is %d, should be 32",
  769. "NetAddr::IP::Util::",subname,len *8);
  770. }
  771. if (ix == 0)
  772. extendipv4(ip, wa);
  773. else
  774. extendmask4(ip, wa);
  775. XPUSHs(sv_2mortal(newSVpvn((char *)wa,16)));
  776. XSRETURN(1);
  777.  
  778. void
  779. ipanyto6(s)
  780. SV * s
  781. ALIAS:
  782. NetAddr::IP::Util::maskanyto6 = 1
  783. PREINIT:
  784. unsigned char * ip;
  785. char * subname;
  786. u_int32_t wa[4];
  787. STRLEN len;
  788. PPCODE:
  789. ip = (unsigned char *) SvPV(s,len);
  790. if (len == 16) /* if already 128 bits, return input */
  791. XPUSHs(sv_2mortal(newSVpvn((char *)ip,16)));
  792. else if (len == 4) {
  793. if (ix == 0)
  794. extendipv4(ip, wa);
  795. else
  796. extendmask4(ip, wa);
  797. XPUSHs(sv_2mortal(newSVpvn((char *)wa,16)));
  798. }
  799. else {
  800. if (ix == 1)
  801. subname = is_maskanyto6;
  802. else
  803. subname = is_ipanyto6;
  804. croak("Bad arg length for %s%s, length is %d, should be 32 or 128",
  805. "NetAddr::IP::Util::",subname,len *8);
  806. }
  807. XSRETURN(1);
  808.