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