File Coverage

object.c
Criterion Covered Total %
statement 485 552 87.8
branch 184 250 73.6
condition n/a
subroutine n/a
pod n/a
total 669 802 83.4


line stmt bran cond sub pod time code
1             /*
2             object.c - Functions for Net::IP::XS's object-oriented interface.
3              
4             Copyright (C) 2010-2016 Tom Harrison
5             Original inet_pton4, inet_pton6 are Copyright (C) 2006 Free Software
6             Foundation.
7             Original interface, and the auth and ip_auth functions, are Copyright
8             (C) 1999-2002 RIPE NCC.
9              
10             This program is free software; you can redistribute it and/or modify
11             it under the terms of the GNU General Public License as published by
12             the Free Software Foundation; either version 2 of the License, or
13             (at your option) any later version.
14              
15             This program is distributed in the hope that it will be useful,
16             but WITHOUT ANY WARRANTY; without even the implied warranty of
17             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18             GNU General Public License for more details.
19              
20             You should have received a copy of the GNU General Public License along
21             with this program; if not, write to the Free Software Foundation, Inc.,
22             51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23             */
24              
25             #include "EXTERN.h"
26             #include "perl.h"
27             #include "XSUB.h"
28              
29             #include "functions.h"
30              
31             #define HV_PV_GET_OR_RETURN(name, object, str, len) \
32             name = NI_hv_get_pv(object, str, len); \
33             if (!name) { return 0; }
34              
35             #define HV_MY_DELETE(object, str, len) \
36             hv_delete((HV*) SvRV(object), str, len, G_DISCARD);
37              
38             #define HV_MY_STORE_IV(object, str, len, var) \
39             hv_store((HV*) SvRV(object), str, len, newSViv(var), 0);
40              
41             #define HV_MY_STORE_UV(object, str, len, var) \
42             hv_store((HV*) SvRV(object), str, len, newSVuv(var), 0);
43              
44             #define HV_MY_STORE_PV(object, str, len, var, varlen) \
45             hv_store((HV*) SvRV(object), str, len, newSVpv(var, varlen), 0);
46              
47             #ifdef __cplusplus
48             extern "C" {
49             #endif
50              
51             /**
52             * NI_object_set_Error_Errno() - set object error number and string.
53             * @ip: Net::IP::XS object.
54             * @Errno: the new error number.
55             * @Error: the new error string (can include printf modifiers).
56             * @...: format arguments to substitute into @Error.
57             */
58             void
59 4           NI_object_set_Error_Errno(SV *ipo, int Errno, const char *Error, ...)
60             {
61             char errtmp[512];
62             va_list args;
63              
64 4           va_start(args, Error);
65 4           vsnprintf(errtmp, 512, Error, args);
66 4           errtmp[511] = '\0';
67              
68 4           HV_MY_STORE_PV(ipo, "error", 5, errtmp, 0);
69 4           HV_MY_STORE_IV(ipo, "errno", 5, Errno);
70              
71 4           va_end(args);
72 4           }
73              
74             /**
75             * NI_copy_Error_Errno() - copy global error details to object.
76             * @ip: Net::IP::XS object.
77             */
78             void
79 18           NI_copy_Error_Errno(SV *ipo)
80             {
81 18           HV_MY_STORE_PV(ipo, "error", 5, NI_get_Error(), 0);
82 18           HV_MY_STORE_IV(ipo, "errno", 5, NI_get_Errno());
83 18           }
84              
85             /**
86             * NI_find_prefixes(): get prefix for Net::IP::XS object.
87             * @ip: Net::IP::XS object.
88             * @prefixes: prefix strings buffer.
89             * @pcount: prefix count buffer.
90             *
91             * See NI_ip_range_to_prefix().
92             */
93             int
94 907           NI_find_prefixes(SV *ipo, char **prefixes, int *pcount)
95             {
96             const char *binip;
97             const char *last_bin;
98             int ipversion;
99             int res;
100              
101 907 50         HV_PV_GET_OR_RETURN(binip, ipo, "binip", 5);
102 907 50         HV_PV_GET_OR_RETURN(last_bin, ipo, "last_bin", 8);
103 907           ipversion = NI_hv_get_iv(ipo, "ipversion", 9);
104              
105 907           res = NI_ip_range_to_prefix(binip, last_bin,
106             ipversion, prefixes, pcount);
107              
108 907 100         if (!res || !(*pcount)) {
    50          
109 1           NI_copy_Error_Errno(ipo);
110 1           return 0;
111             }
112              
113 906           return 1;
114             }
115              
116             /**
117             * NI_set_ipv6_n128s(): set N128 integers in IPv6 Net::IP::XS object.
118             * @ip: Net::IP::XS object.
119             *
120             * Relies on 'binip' and 'last_bin' being set in the object.
121             */
122             int
123 400           NI_set_ipv6_n128s(SV *ipo)
124             {
125             n128_t ipv6_begin;
126             n128_t ipv6_end;
127             const char *binbuf1;
128             const char *binbuf2;
129             SV *begin;
130             SV *end;
131              
132 400 50         HV_PV_GET_OR_RETURN(binbuf1, ipo, "binip", 5);
133 400 50         HV_PV_GET_OR_RETURN(binbuf2, ipo, "last_bin", 8);
134              
135 400           n128_set_str_binary(&ipv6_begin, binbuf1, 128);
136 400           n128_set_str_binary(&ipv6_end, binbuf2, 128);
137              
138             /* Previously, this part of the code used malloc to allocate
139             * n128_ts, which were then stored within the Net::IP::XS object.
140             * This didn't work properly when threads were in use, because
141             * those raw pointers were copied to each new thread, and
142             * consequently freed by each thread in DESTROY. This now stores
143             * the raw data as PVs instead. See
144             * https://rt.cpan.org/Ticket/Display.html?id=102155 for more
145             * information. */
146              
147 400           begin = newSVpv((const char*) &ipv6_begin, 16);
148 400           end = newSVpv((const char*) &ipv6_end, 16);
149              
150 400           hv_store((HV*) SvRV(ipo), "xs_v6_ip0", 9, begin, 0);
151 400           hv_store((HV*) SvRV(ipo), "xs_v6_ip1", 9, end, 0);
152              
153 400           return 1;
154             }
155              
156             /**
157             * NI_set(): construct a new Net::IP::XS object.
158             * @ip: Net::IP::XS object (can be initialised).
159             * @version: IP address version.
160             */
161             int
162 914           NI_set(SV* ipo, char *data, int ipversion)
163             {
164             char buf1[MAX_IPV6_STR_LEN];
165             char buf2[MAX_IPV6_STR_LEN];
166             char binbuf1[IPV6_BITSTR_LEN];
167             char binbuf2[IPV6_BITSTR_LEN];
168             char maskbuf[IPV6_BITSTR_LEN];
169             char prefixbuf[MAX_IPV6_STR_LEN];
170             char *prefixes[MAX_PREFIXES];
171             char *binbuf2p;
172             int res;
173             int cmp_res;
174             int num_addrs;
175             int endipversion;
176             int iplen;
177             int pcount;
178             int prefixlen;
179             int i;
180              
181 914           buf1[0] = '\0';
182 914           buf2[0] = '\0';
183              
184 914           binbuf1[0] = '\0';
185 914           binbuf2[0] = '\0';
186 914           maskbuf[0] = '\0';
187              
188 914           num_addrs = NI_ip_normalize(data, buf1, buf2);
189 914 100         if (!num_addrs) {
190 5           NI_copy_Error_Errno(ipo);
191 5           return 0;
192             }
193              
194 909           HV_MY_DELETE(ipo, "ipversion", 9);
195 909           HV_MY_DELETE(ipo, "prefixlen", 9);
196 909           HV_MY_DELETE(ipo, "binmask", 7);
197 909           HV_MY_DELETE(ipo, "reverse_ip", 10);
198 909           HV_MY_DELETE(ipo, "last_ip", 7);
199 909           HV_MY_DELETE(ipo, "iptype", 6);
200 909           HV_MY_DELETE(ipo, "binip", 5);
201 909           HV_MY_DELETE(ipo, "error", 5);
202 909           HV_MY_DELETE(ipo, "ip", 2);
203 909           HV_MY_DELETE(ipo, "intformat", 9);
204 909           HV_MY_DELETE(ipo, "mask", 4);
205 909           HV_MY_DELETE(ipo, "last_bin", 8);
206 909           HV_MY_DELETE(ipo, "last_int", 8);
207 909           HV_MY_DELETE(ipo, "prefix", 6);
208 909           HV_MY_DELETE(ipo, "is_prefix", 9);
209              
210 909 100         if (!ipversion) {
211 83           ipversion = NI_ip_get_version(buf1);
212 83 50         if (!ipversion) {
213 0           return 0;
214             }
215             }
216              
217 909           iplen = NI_iplengths(ipversion);
218 909 100         if (!iplen) {
219 1           return 0;
220             }
221              
222 908           HV_MY_STORE_IV(ipo, "ipversion", 9, ipversion);
223 908           HV_MY_STORE_PV(ipo, "ip", 2, buf1, 0);
224              
225 908           binbuf1[iplen] = '\0';
226 908           res = NI_ip_iptobin(buf1, ipversion, binbuf1);
227 908 50         if (!res) {
228 0           return 0;
229             }
230              
231 908           HV_MY_STORE_PV(ipo, "binip", 5, binbuf1, iplen);
232 908           HV_MY_STORE_IV(ipo, "is_prefix", 9, 0);
233              
234 908 100         if (num_addrs == 1) {
235 22           HV_MY_STORE_PV(ipo, "last_ip", 7, buf1, 0);
236 22           HV_MY_STORE_PV(ipo, "last_bin", 8, binbuf1, iplen);
237 22           binbuf2p = binbuf1;
238             } else {
239 886           endipversion = NI_ip_get_version(buf2);
240 886 50         if (!endipversion) {
241 0           return 0;
242             }
243 886 50         if (endipversion != ipversion) {
244 0           NI_set_Error_Errno(201, "Begin and End addresses have "
245             "different IP versions - %s - %s",
246             buf1, buf2);
247 0           NI_copy_Error_Errno(ipo);
248 0           return 0;
249             }
250              
251 886           binbuf2[iplen] = '\0';
252 886           res = NI_ip_iptobin(buf2, ipversion, binbuf2);
253 886 50         if (!res) {
254 0           return 0;
255             }
256              
257 886           HV_MY_STORE_PV(ipo, "last_ip", 7, buf2, 0);
258 886           HV_MY_STORE_PV(ipo, "last_bin", 8, binbuf2, iplen);
259              
260 886           res = NI_ip_bincomp(binbuf1, "le", binbuf2, &cmp_res);
261 886 50         if (!res) {
262 0           return 0;
263             }
264 886 100         if (!cmp_res) {
265 2           NI_set_Error_Errno(202, "Begin address is greater than End "
266             "address %s - %s",
267             buf1, buf2);
268 2           NI_copy_Error_Errno(ipo);
269 2           return 0;
270             }
271 884           binbuf2p = binbuf2;
272             }
273              
274 906           pcount = 0;
275 906           res = NI_find_prefixes(ipo, prefixes, &pcount);
276 906 50         if (!res) {
277 0           return 0;
278             }
279              
280 906 100         if (pcount == 1) {
281 134           char *prefix = prefixes[0];
282              
283 134           res = NI_ip_splitprefix(prefix, prefixbuf, &prefixlen);
284 134 50         if (!res) {
285 0           free(prefix);
286 0           return 0;
287             }
288              
289 134           NI_ip_get_mask(prefixlen, ipversion, maskbuf);
290              
291 134           res = NI_ip_check_prefix(binbuf1, prefixlen, ipversion);
292 134 50         if (!res) {
293 0           free(prefix);
294 0           NI_copy_Error_Errno(ipo);
295 0           return 0;
296             }
297              
298 134           HV_MY_STORE_IV(ipo, "prefixlen", 9, prefixlen);
299 134           HV_MY_STORE_IV(ipo, "is_prefix", 9, 1);
300 134           HV_MY_STORE_PV(ipo, "binmask", 7, maskbuf, iplen);
301             }
302              
303 22210 100         for (i = 0; i < pcount; i++) {
304 21304           free(prefixes[i]);
305             }
306              
307 906 100         if (ipversion == 4) {
308 506           HV_MY_STORE_UV(ipo, "xs_v4_ip0", 9, NI_bintoint(binbuf1, 32));
309 506           HV_MY_STORE_UV(ipo, "xs_v4_ip1", 9, NI_bintoint(binbuf2p, 32));
310             } else {
311 400           res = NI_set_ipv6_n128s(ipo);
312 400 50         if (!res) {
313 0           return 0;
314             }
315             }
316              
317 914           return 1;
318             }
319              
320             /**
321             * NI_get_begin_n128(): get first address of IPv6 object as N128 integer.
322             * @ip: Net::IP::XS object.
323             * @begin: reference to N128 integer.
324             *
325             * On success, @begin will point to the beginning address stored in
326             * the IPv6 object.
327             */
328             int
329 377           NI_get_begin_n128(SV *ipo, n128_t *begin)
330             {
331             SV **ref;
332             STRLEN len;
333             const char *raw_begin;
334              
335 377           ref = hv_fetch((HV*) SvRV(ipo), "xs_v6_ip0", 9, 0);
336 377 50         if (!ref || !(*ref)) {
    50          
337 0           return 0;
338             }
339 377 50         raw_begin = SvPV(*ref, len);
340 377           memcpy(begin, raw_begin, 16);
341              
342 377           return 1;
343             }
344              
345             /**
346             * NI_get_end_n128(): get last address of IPv6 object as N128 integer.
347             * @ip: Net::IP::XS object.
348             * @end: reference to N128 integer.
349             *
350             * On success, @end will point to the ending address stored in the
351             * IPv6 object.
352             */
353             int
354 376           NI_get_end_n128(SV *ipo, n128_t *end)
355             {
356             SV **ref;
357             STRLEN len;
358             const char *raw_end;
359              
360 376           ref = hv_fetch((HV*) SvRV(ipo), "xs_v6_ip1", 9, 0);
361 376 50         if (!ref || !(*ref)) {
    50          
362 0           return 0;
363             }
364 376 50         raw_end = SvPV(*ref, len);
365 376           memcpy(end, raw_end, 16);
366              
367 376           return 1;
368             }
369              
370             /**
371             * NI_get_n128s(): get begin-end addresses of IPv6 object as N128 integers.
372             * @ip: Net::IP::XS object.
373             * @begin: reference to N128 integer.
374             * @end: reference to N128 integer.
375             *
376             * See NI_get_begin_n128() and NI_get_end_n128().
377             */
378             int
379 368           NI_get_n128s(SV *ipo, n128_t *begin, n128_t *end)
380             {
381 736           return NI_get_begin_n128(ipo, begin)
382 368 50         && NI_get_end_n128(ipo, end);
    50          
383             }
384              
385             /**
386             * NI_short(): get the short format of the first IP address in the object.
387             * @ip: Net::IP::XS object.
388             * @buf: buffer for short format string.
389             *
390             * @buf will be null-terminated on success.
391             */
392             int
393 37           NI_short(SV *ipo, char *buf)
394             {
395             int version;
396             int prefixlen;
397             int res;
398             const char *ipstr;
399              
400 37           version = NI_hv_get_iv(ipo, "ipversion", 9);
401 37           ipstr = NI_hv_get_pv(ipo, "ip", 2);
402 37 100         if (!ipstr) {
403 1           ipstr = "";
404             }
405              
406 37 100         if (version == 6) {
407 1           res = NI_ip_compress_address(ipstr, 6, buf);
408             } else {
409 36           prefixlen = NI_hv_get_iv(ipo, "prefixlen", 9);
410 36           res = NI_ip_compress_v4_prefix(ipstr, prefixlen, buf, 40);
411             }
412              
413 37 100         if (!res) {
414 1           NI_copy_Error_Errno(ipo);
415 1           return 0;
416             }
417              
418 36           return 1;
419             }
420              
421             /**
422             * NI_last_ip(): get last IP address of a range as a string.
423             * @ipo: Net::IP::XS object.
424             * @buf: IP address buffer.
425             * @maxlen: maximum capacity of buffer.
426             */
427             int
428 12           NI_last_ip(SV *ipo, char *buf, int maxlen)
429             {
430             const char *last_ip;
431             const char *last_bin;
432             int version;
433             int res;
434              
435 12 100         if ((last_ip = NI_hv_get_pv(ipo, "last_ip", 7))) {
436 10           snprintf(buf, maxlen, "%s", last_ip);
437 10           return 1;
438             }
439              
440 2           last_bin = NI_hv_get_pv(ipo, "last_bin", 8);
441 2 100         if (!last_bin) {
442 1           last_bin = "";
443             }
444              
445 2           version = NI_hv_get_iv(ipo, "ipversion", 9);
446              
447 2           res = NI_ip_bintoip(last_bin, version, buf);
448 2 100         if (!res) {
449 1           NI_copy_Error_Errno(ipo);
450 1           return 0;
451             }
452              
453 1           HV_MY_STORE_PV(ipo, "last_ip", 7, buf, 0);
454              
455 1           return 1;
456             }
457              
458             /**
459             * NI_print(): get the IP address/range in string format.
460             * @ip: Net::IP::XS object.
461             * @buf: buffer for the string.
462             *
463             * If the object represents a single prefix, the buffer will get the
464             * short format of the first address (as per NI_short()), plus a '/',
465             * plus the prefix length. Otherwise, it will get the first address,
466             * plus " - ", plus the last address (neither in short (compressed)
467             * format).
468             */
469             int
470 7           NI_print(SV *ipo, char *buf, int maxlen)
471             {
472             int is_prefix;
473             int prefixlen;
474             const char *first_ip;
475             const char *second_ip;
476             int res;
477             char mybuf[MAX_IPV6_STR_LEN];
478              
479 7           is_prefix = NI_hv_get_iv(ipo, "is_prefix", 9);
480              
481 7 100         if (is_prefix) {
482 3           res = NI_short(ipo, mybuf);
483 3 100         if (!res) {
484 1           return 0;
485             }
486 2           prefixlen = NI_hv_get_iv(ipo, "prefixlen", 9);
487 2           snprintf(buf, maxlen, "%s/%d", mybuf, prefixlen);
488             } else {
489 4           first_ip = NI_hv_get_pv(ipo, "ip", 2);
490 4 100         if (!first_ip) {
491 1           return 0;
492             }
493              
494 3           NI_last_ip(ipo, mybuf, MAX_IPV6_STR_LEN);
495 3           second_ip = NI_hv_get_pv(ipo, "last_ip", 7);
496 3 50         if (!second_ip) {
497 0           return 0;
498             }
499              
500 3           snprintf(buf, maxlen, "%s - %s", first_ip, second_ip);
501             }
502              
503 7           return 1;
504             }
505              
506             /**
507             * NI_size_str_ipv4(): get size of IPv4 object as a string.
508             * @ip: Net::IP::XS object.
509             * @buf: size buffer.
510             */
511             int
512 9           NI_size_str_ipv4(SV *ipo, char *buf)
513             {
514             unsigned long begin;
515             unsigned long end;
516              
517 9           begin = NI_hv_get_uv(ipo, "xs_v4_ip0", 9);
518 9           end = NI_hv_get_uv(ipo, "xs_v4_ip1", 9);
519              
520 9 100         if ((begin == 0) && (end == 0xFFFFFFFF)) {
    100          
521 3           sprintf(buf, "4294967296");
522             } else {
523 6           sprintf(buf, "%lu", end - begin + 1);
524             }
525              
526 9           return 1;
527             }
528              
529             /**
530             * NI_size_str_ipv6(): get size of IPv6 object as a string.
531             * @ip: Net::IP::XS object.
532             * @buf: size buffer.
533             */
534             int
535 8           NI_size_str_ipv6(SV *ipo, char *buf)
536             {
537             n128_t begin;
538             n128_t end;
539             int res;
540              
541 8           res = NI_get_n128s(ipo, &begin, &end);
542 8 50         if (!res) {
543 0           return 0;
544             }
545              
546 8 50         if ( n128_scan1(&begin) == INT_MAX
547 8 100         && n128_scan0(&end) == INT_MAX) {
548 7           sprintf(buf, "340282366920938463463374607431768211456");
549 7           return 1;
550             }
551              
552 1           n128_sub(&end, &begin);
553 1           n128_add_ui(&end, 1);
554 1           n128_print_dec(&end, buf);
555              
556 8           return 1;
557             }
558              
559             /**
560             * NI_size_str(): get size of Net::IP::XS object as a string.
561             * @ip: Net::IP::XS object.
562             * @buf: size buffer.
563             *
564             * See NI_size_str_ipv4() and NI_size_str_ipv6().
565             */
566             int
567 19           NI_size_str(SV *ipo, char *size)
568             {
569 19           switch (NI_hv_get_iv(ipo, "ipversion", 9)) {
570 9           case 4: return NI_size_str_ipv4(ipo, size);
571 8           case 6: return NI_size_str_ipv6(ipo, size);
572 2           default: return 0;
573             }
574             }
575              
576             /**
577             * NI_intip_str_ipv4(): get first IP address as an integer string.
578             * @ip: Net::IP::XS object.
579             * @buf: integer string buffer.
580             */
581             int
582 9           NI_intip_str_ipv4(SV *ipo, char *buf)
583             {
584 9           sprintf(buf, "%lu", (unsigned long) NI_hv_get_uv(ipo, "xs_v4_ip0", 9));
585              
586 9           return 1;
587             }
588              
589             /**
590             * NI_intip_str_ipv6(): get first IP address as an integer string.
591             * @ip: Net::IP::XS object.
592             * @buf: integer string buffer.
593             */
594             int
595 7           NI_intip_str_ipv6(SV *ipo, char *buf)
596             {
597             n128_t begin;
598              
599 7 50         if (!NI_get_begin_n128(ipo, &begin)) {
600 0           return 0;
601             }
602              
603 7           n128_print_dec(&begin, buf);
604              
605 7           return 1;
606             }
607              
608             /**
609             * NI_intip_str(): get first IP address as an integer string.
610             * @ip: Net::IP::XS object.
611             * @buf: integer string buffer.
612             * @maxlen: maximum capacity of buffer.
613             */
614             int
615 19           NI_intip_str(SV *ipo, char *buf, int maxlen)
616             {
617             const char *intformat;
618             int res;
619              
620 19 100         if ((intformat = NI_hv_get_pv(ipo, "intformat", 9))) {
621 1           snprintf(buf, maxlen, "%s", intformat);
622 1           return 1;
623             }
624              
625 18           switch (NI_hv_get_iv(ipo, "ipversion", 9)) {
626 9           case 4: res = NI_intip_str_ipv4(ipo, buf); break;
627 7           case 6: res = NI_intip_str_ipv6(ipo, buf); break;
628 2           default: res = 0;
629             }
630              
631 18 100         if (res) {
632 16           HV_MY_STORE_PV(ipo, "intformat", 9, buf, strlen(buf));
633             }
634              
635 18           return res;
636             }
637              
638             /**
639             * NI_hexip_ipv4(): get first IP address as a hex string.
640             * @ip: Net::IP::XS object.
641             * @buf: hex string buffer.
642             *
643             * The string has '0x' prefixed to it.
644             */
645             int
646 2           NI_hexip_ipv4(SV *ipo, char *buf)
647             {
648 2           sprintf(buf, "0x%lx", (unsigned long) NI_hv_get_uv(ipo, "xs_v4_ip0", 9));
649              
650 2           return 1;
651             }
652              
653             /**
654             * NI_hexip_ipv6(): get first IP address as a hex string.
655             * @ip: Net::IP::XS object.
656             * @buf: hex string buffer.
657             *
658             * The string has '0x' prefixed to it.
659             */
660             int
661 2           NI_hexip_ipv6(SV *ipo, char *hexip)
662             {
663             n128_t begin;
664              
665 2 50         if (!NI_get_begin_n128(ipo, &begin)) {
666 0           return 0;
667             }
668              
669 2           n128_print_hex(&begin, hexip);
670              
671 2           return 1;
672             }
673              
674             /**
675             * NI_hexip(): get first IP address as a hex string.
676             * @ip: Net::IP::XS object.
677             * @buf: hex string buffer.
678             * @maxlen: maximum capacity of buffer.
679             *
680             * See NI_hexip_ipv4() and NI_hexip_ipv6().
681             */
682             int
683 7           NI_hexip(SV *ipo, char *buf, int maxlen)
684             {
685             const char *hexformat;
686             int res;
687              
688 7 100         if ((hexformat = NI_hv_get_pv(ipo, "hexformat", 9))) {
689 1           snprintf(buf, maxlen, "%s", hexformat);
690 1           return 1;
691             }
692              
693 6           switch (NI_hv_get_iv(ipo, "ipversion", 9)) {
694 2           case 4: res = NI_hexip_ipv4(ipo, buf); break;
695 2           case 6: res = NI_hexip_ipv6(ipo, buf); break;
696 2           default: res = 0;
697             }
698              
699 6 100         if (res) {
700 4           HV_MY_STORE_PV(ipo, "hexformat", 9, buf, strlen(buf));
701             }
702              
703 6           return res;
704             }
705              
706             /**
707             * NI_hexmask(): return network mask as a hex string.
708             * @ip: Net::IP::XS object.
709             * @buf: hex string buffer.
710             * @maxlen: maximum capacity of buffer.
711             */
712             int
713 7           NI_hexmask(SV *ipo, char *buf, int maxlen)
714             {
715             const char *binmask;
716             const char *hexmask;
717             n128_t dec;
718              
719 7 100         if ((hexmask = NI_hv_get_pv(ipo, "hexmask", 7))) {
720 1           snprintf(buf, maxlen, "%s", hexmask);
721 1           return 1;
722             }
723              
724             /* Net::IP continues with the ip_bintoint call regardless of
725             * whether binmask is defined, but that won't produce reasonable
726             * output anyway, so will return undef instead. */
727              
728 6 100         HV_PV_GET_OR_RETURN(binmask, ipo, "binmask", 7);
729              
730 5           n128_set_str_binary(&dec, binmask, strlen(binmask));
731 5           n128_print_hex(&dec, buf);
732 5           HV_MY_STORE_PV(ipo, "hexmask", 7, buf, strlen(buf));
733              
734 7           return 1;
735             }
736              
737             /**
738             * NI_prefix(): return range in prefix format.
739             * @ipo: Net::IP::XS object.
740             * @buf: prefix buffer.
741             * @maxlen: maximum capacity of buffer.
742             *
743             * Sets Error and Errno in the object if the object does not represent
744             * a single prefix.
745             */
746             int
747 8           NI_prefix(SV *ipo, char *buf, int maxlen)
748             {
749             const char *ip;
750             const char *prefix;
751             int is_prefix;
752             int prefixlen;
753              
754 8           ip = NI_hv_get_pv(ipo, "ip", 2);
755 8 100         if (!ip) {
756 1           ip = "";
757             }
758              
759 8           is_prefix = NI_hv_get_iv(ipo, "is_prefix", 9);
760 8 100         if (!is_prefix) {
761 1           NI_object_set_Error_Errno(ipo, 209, "IP range %s is not a Prefix.",
762             ip);
763 1           return 0;
764             }
765              
766 7 100         if ((prefix = NI_hv_get_pv(ipo, "prefix", 6))) {
767 1           snprintf(buf, maxlen, "%s", prefix);
768 1           return 1;
769             }
770              
771 6           prefixlen = NI_hv_get_iv(ipo, "prefixlen", 9);
772 6 100         if (prefixlen == -1) {
773 1           return 0;
774             }
775 5           snprintf(buf, maxlen, "%s/%d", ip, prefixlen);
776 5           HV_MY_STORE_PV(ipo, "prefix", 6, buf, 0);
777              
778 5           return 1;
779             }
780              
781             /**
782             * NI_mask(): return the IP address mask in IP address format.
783             * @ipo: Net::IP::XS object.
784             * @buf: mask buffer.
785             * @maxlen: maximum capacity of buffer.
786             */
787             int
788 9           NI_mask(SV *ipo, char *buf, int maxlen)
789             {
790             const char *mask;
791             const char *binmask;
792             const char *ip;
793             int is_prefix;
794             int version;
795             int res;
796              
797 9           is_prefix = NI_hv_get_iv(ipo, "is_prefix", 9);
798 9 100         if (!is_prefix) {
799 2           ip = NI_hv_get_pv(ipo, "ip", 2);
800 2 100         if (!ip) {
801 1           ip = "";
802             }
803              
804 2           NI_object_set_Error_Errno(ipo, 209, "IP range %s is not a Prefix.",
805             ip);
806 2           return 0;
807             }
808              
809 7 100         if ((mask = NI_hv_get_pv(ipo, "mask", 4))) {
810 1           snprintf(buf, maxlen, "%s", mask);
811 1           return 1;
812             }
813              
814 6           binmask = NI_hv_get_pv(ipo, "binmask", 7);
815 6 100         if (!binmask) {
816 1           binmask = "";
817             }
818              
819 6           version = NI_hv_get_iv(ipo, "ipversion", 9);
820              
821 6           res = NI_ip_bintoip(binmask, version, buf);
822 6 100         if (!res) {
823 1           NI_copy_Error_Errno(ipo);
824 1           return 0;
825             }
826              
827 5           HV_MY_STORE_PV(ipo, "mask", 4, buf, 0);
828              
829 5           return 1;
830             }
831              
832             /**
833             * NI_iptype(): get the type of the first IP address in the object.
834             * @ipo: Net::IP::XS object.
835             * @buf: type buffer.
836             * @maxlen: maximum capacity of buffer.
837             *
838             * See NI_ip_iptype().
839             */
840             int
841 7           NI_iptype(SV *ipo, char *buf, int maxlen)
842             {
843             const char *binip;
844             const char *iptype;
845             int version;
846             int res;
847              
848 7 100         if ((iptype = NI_hv_get_pv(ipo, "iptype", 6))) {
849 1           snprintf(buf, maxlen, "%s", iptype);
850 1           return 1;
851             }
852              
853 6           binip = NI_hv_get_pv(ipo, "binip", 5);
854 6 100         if (!binip) {
855 1           binip = "";
856             }
857              
858 6           version = NI_hv_get_iv(ipo, "ipversion", 9);
859              
860 6           res = NI_ip_iptype(binip, version, buf);
861 6 100         if (!res) {
862 2           NI_copy_Error_Errno(ipo);
863 2           return 0;
864             }
865              
866 4           HV_MY_STORE_PV(ipo, "iptype", 6, buf, 0);
867              
868 4           return 1;
869             }
870              
871             /**
872             * NI_reverse_ip(): get reverse domain for the first address of an object.
873             * @ipo: Net::IP::XS object.
874             * @buf: reverse domain buffer.
875             *
876             * See NI_ip_reverse().
877             */
878             int
879 6           NI_reverse_ip(SV *ipo, char *buf)
880             {
881             const char *ip;
882             int prefixlen;
883             int version;
884             int res;
885              
886 6           ip = NI_hv_get_pv(ipo, "ip", 2);
887 6 100         if (!ip) {
888 1           ip = "";
889             }
890              
891 6 100         if (!NI_hv_get_iv(ipo, "is_prefix", 9)) {
892 1           NI_object_set_Error_Errno(ipo, 209, "IP range %s is not a Prefix.",
893             ip);
894 1           return 0;
895             }
896              
897 5           prefixlen = NI_hv_get_iv(ipo, "prefixlen", 9);
898 5           version = NI_hv_get_iv(ipo, "ipversion", 9);
899              
900 5           res = NI_ip_reverse(ip, prefixlen, version, buf);
901              
902 5 100         if (!res) {
903 1           NI_copy_Error_Errno(ipo);
904 1           return 0;
905             }
906              
907 4           return 1;
908             }
909              
910             /**
911             * NI_last_bin(): get the last IP address of a range as a bitstring.
912             * @ipo: Net::IP::XS object.
913             * @buf: bitstring buffer.
914             * @maxlen: maximum capacity of buffer.
915             */
916             int
917 13           NI_last_bin(SV *ipo, char *buf, int maxlen)
918             {
919             const char *last_bin;
920             const char *binip;
921             const char *last_ip;
922             int version;
923             int is_prefix;
924             int prefixlen;
925             int res;
926              
927 13 100         if ((last_bin = NI_hv_get_pv(ipo, "last_bin", 8))) {
928 8           snprintf(buf, maxlen, "%s", last_bin);
929 8           return 1;
930             }
931              
932 5           is_prefix = NI_hv_get_iv(ipo, "is_prefix", 9);
933 5           version = NI_hv_get_iv(ipo, "ipversion", 9);
934              
935 5 100         if (is_prefix) {
936 2           binip = NI_hv_get_pv(ipo, "binip", 5);
937 2 100         if (!binip) {
938 1           return 0;
939             }
940 1           prefixlen = NI_hv_get_iv(ipo, "prefixlen", 9);
941 1           res = NI_ip_last_address_bin(binip, prefixlen, version, buf);
942             } else {
943 3           last_ip = NI_hv_get_pv(ipo, "last_ip", 7);
944 3 100         if (!last_ip) {
945 1           return 0;
946             }
947 2           res = NI_ip_iptobin(last_ip, version, buf);
948             }
949              
950 3 100         if (!res) {
951 1           NI_copy_Error_Errno(ipo);
952 1           return 0;
953             }
954              
955 2           buf[NI_iplengths(version)] = '\0';
956              
957 2           HV_MY_STORE_PV(ipo, "last_bin", 8, buf, 0);
958              
959 2           return 1;
960             }
961              
962             /**
963             * NI_last_int_str_ipv4(): get last IP address of a range as an integer string.
964             * @ipo: Net::IP::XS object.
965             * @buf: integer string buffer.
966             */
967 7           int NI_last_int_str_ipv4(SV *ipo, char *buf)
968             {
969             unsigned long end;
970              
971 7           end = NI_hv_get_uv(ipo, "xs_v4_ip1", 9);
972 7           sprintf(buf, "%lu", end);
973              
974 7           return 1;
975             }
976              
977             /**
978             * NI_last_int_str_ipv6(): get last IP address of a range as an integer string.
979             * @ipo: Net::IP::XS object.
980             * @buf: integer string buffer.
981             */
982 8           int NI_last_int_str_ipv6(SV *ipo, char *buf)
983             {
984             n128_t end;
985              
986 8 50         if (!NI_get_end_n128(ipo, &end)) {
987 0           return 0;
988             }
989              
990 8           n128_print_dec(&end, buf);
991              
992 8           return 1;
993             }
994              
995             /**
996             * NI_last_int_str(): get last IP address of a range as an integer string.
997             * @ipo: Net::IP::XS object.
998             * @buf: integer string buffer.
999             * @maxlen: maximum capacity of buffer.
1000             */
1001             int
1002 18           NI_last_int_str(SV *ipo, char *buf, int maxlen)
1003             {
1004             const char *last_int;
1005             int res;
1006              
1007 18 100         if ((last_int = NI_hv_get_pv(ipo, "last_int", 8))) {
1008 1           snprintf(buf, maxlen, "%s", last_int);
1009 1           return 1;
1010             }
1011              
1012 17           switch (NI_hv_get_iv(ipo, "ipversion", 9)) {
1013 7           case 4: res = NI_last_int_str_ipv4(ipo, buf); break;
1014 8           case 6: res = NI_last_int_str_ipv6(ipo, buf); break;
1015 2           default: res = 0;
1016             }
1017              
1018 17 100         if (res) {
1019 15           HV_MY_STORE_PV(ipo, "last_int", 8, buf, 0);
1020             }
1021              
1022 17           return res;
1023             }
1024              
1025             /**
1026             * NI_bincomp(): compare first IP addresses of two ranges.
1027             * @ipo1: first Net::IP::XS object.
1028             * @op: the comparator as a string.
1029             * @ipo2: second Net::IP::XS object.
1030             * @buf: result buffer.
1031             *
1032             * See NI_ip_bincomp().
1033             */
1034             int
1035 4           NI_bincomp(SV *ipo1, const char *op, SV *ipo2, int *resbuf)
1036             {
1037             const char *binip1;
1038             const char *binip2;
1039             int res;
1040              
1041 4           binip1 = NI_hv_get_pv(ipo1, "binip", 5);
1042 4 100         if (!binip1) {
1043 1           binip1 = "";
1044             }
1045              
1046 4           binip2 = NI_hv_get_pv(ipo2, "binip", 5);
1047 4 100         if (!binip2) {
1048 1           binip2 = "";
1049             }
1050              
1051 4           res = NI_ip_bincomp(binip1, op, binip2, resbuf);
1052 4 100         if (!res) {
1053 1           NI_copy_Error_Errno(ipo1);
1054 1           return 0;
1055             }
1056              
1057 3           return 1;
1058             }
1059              
1060             /**
1061             * NI_binadd(): get new object from the sum of two IP addresses.
1062             * @ipo1: first Net::IP::XS object.
1063             * @ipo2: second Net::IP::XS object.
1064             */
1065             SV *
1066 4           NI_binadd(SV *ipo1, SV *ipo2)
1067             {
1068             const char *binip1;
1069             const char *binip2;
1070             int version;
1071             char binbuf[130];
1072             char buf[45];
1073             int res;
1074             HV *stash;
1075             HV *hash;
1076             SV *ref;
1077             int iplen;
1078              
1079 4           binip1 = NI_hv_get_pv(ipo1, "binip", 5);
1080 4 100         if (!binip1) {
1081 1           binip1 = "";
1082             }
1083              
1084 4           binip2 = NI_hv_get_pv(ipo2, "binip", 5);
1085 4 100         if (!binip2) {
1086 1           binip2 = "";
1087             }
1088              
1089 4           res = NI_ip_binadd(binip1, binip2, binbuf, IPV6_BITSTR_LEN);
1090 4 100         if (!res) {
1091 1           NI_copy_Error_Errno(ipo1);
1092 1           return NULL;
1093             }
1094              
1095 3           version = NI_hv_get_iv(ipo1, "ipversion", 9);
1096 3           iplen = NI_iplengths(version);
1097 3           binbuf[iplen] = '\0';
1098 3           buf[0] = '\0';
1099              
1100 3           res = NI_ip_bintoip(binbuf, version, buf);
1101 3 50         if (!res) {
1102 0           return NULL;
1103             }
1104              
1105 3           hash = newHV();
1106 3           ref = newRV_noinc((SV*) hash);
1107 3           stash = gv_stashpv("Net::IP::XS", 1);
1108 3           sv_bless(ref, stash);
1109 3           res = NI_set(ref, buf, version);
1110 3 50         if (!res) {
1111 0           return NULL;
1112             }
1113              
1114 4           return ref;
1115             }
1116              
1117             /**
1118             * NI_aggregate_ipv4(): aggregate two IP address ranges into new object.
1119             * @ipo1: first Net::IP::XS object.
1120             * @ipo2: second Net::IP::XS object.
1121             */
1122             int
1123 1           NI_aggregate_ipv4(SV *ipo1, SV *ipo2, char *buf)
1124             {
1125             unsigned long b1;
1126             unsigned long b2;
1127             unsigned long e1;
1128             unsigned long e2;
1129             const char *ip1;
1130             const char *ip2;
1131             int res;
1132              
1133 1           b1 = NI_hv_get_uv(ipo1, "xs_v4_ip0", 9);
1134 1           e1 = NI_hv_get_uv(ipo1, "xs_v4_ip1", 9);
1135 1           b2 = NI_hv_get_uv(ipo2, "xs_v4_ip0", 9);
1136 1           e2 = NI_hv_get_uv(ipo2, "xs_v4_ip1", 9);
1137              
1138 1           res = NI_ip_aggregate_ipv4(b1, e1, b2, e2, 4, buf);
1139 1 50         if (res == 0) {
1140 0           NI_copy_Error_Errno(ipo1);
1141 0           return 0;
1142             }
1143 1 50         if (res == 160) {
1144 0           ip1 = NI_hv_get_pv(ipo1, "last_ip", 7);
1145 0 0         if (!ip1) {
1146 0           ip1 = "";
1147             }
1148 0           ip2 = NI_hv_get_pv(ipo2, "ip", 2);
1149 0 0         if (!ip2) {
1150 0           ip2 = "";
1151             }
1152 0           NI_set_Error_Errno(160, "Ranges not contiguous - %s - %s",
1153             ip1, ip2);
1154 0           NI_copy_Error_Errno(ipo1);
1155 0           return 0;
1156             }
1157 1 50         if (res == 161) {
1158 0           ip1 = NI_hv_get_pv(ipo1, "ip", 7);
1159 0 0         if (!ip1) {
1160 0           ip1 = "";
1161             }
1162 0           ip2 = NI_hv_get_pv(ipo2, "last_ip", 2);
1163 0 0         if (!ip2) {
1164 0           ip2 = "";
1165             }
1166 0           NI_set_Error_Errno(161, "%s - %s is not a single prefix",
1167             ip1, ip2);
1168 0           NI_copy_Error_Errno(ipo1);
1169 0           return 0;
1170             }
1171              
1172 1           return 1;
1173             }
1174              
1175             /**
1176             * NI_aggregate_ipv6(): aggregate two IP address ranges into new object.
1177             * @ipo1: first Net::IP::XS object.
1178             * @ipo2: second Net::IP::XS object.
1179             */
1180             int
1181 2           NI_aggregate_ipv6(SV *ipo1, SV *ipo2, char *buf)
1182             {
1183             n128_t b1;
1184             n128_t e1;
1185             n128_t b2;
1186             n128_t e2;
1187             int res;
1188             const char *ip1;
1189             const char *ip2;
1190              
1191 2 50         if (!NI_get_n128s(ipo1, &b1, &e1)) {
1192 0           return 0;
1193             }
1194 2 50         if (!NI_get_n128s(ipo2, &b2, &e2)) {
1195 0           return 0;
1196             }
1197              
1198 2           res = NI_ip_aggregate_ipv6(&b1, &e1, &b2, &e2, 6, buf);
1199              
1200 2 50         if (res == 0) {
1201 0           NI_copy_Error_Errno(ipo1);
1202 0           return 0;
1203             }
1204 2 100         if (res == 160) {
1205 1           ip1 = NI_hv_get_pv(ipo1, "last_ip", 7);
1206 1 50         if (!ip1) {
1207 0           ip1 = "";
1208             }
1209 1           ip2 = NI_hv_get_pv(ipo2, "ip", 2);
1210 1 50         if (!ip2) {
1211 0           ip2 = "";
1212             }
1213 1           NI_set_Error_Errno(160, "Ranges not contiguous - %s - %s",
1214             ip1, ip2);
1215 1           NI_copy_Error_Errno(ipo1);
1216 1           return 0;
1217             }
1218 1 50         if (res == 161) {
1219 0           ip1 = NI_hv_get_pv(ipo1, "ip", 7);
1220 0 0         if (!ip1) {
1221 0           ip1 = "";
1222             }
1223 0           ip2 = NI_hv_get_pv(ipo2, "last_ip", 2);
1224 0 0         if (!ip2) {
1225 0           ip2 = "";
1226             }
1227 0           NI_set_Error_Errno(161, "%s - %s is not a single prefix",
1228             ip1, ip2);
1229 0           NI_copy_Error_Errno(ipo1);
1230 0           return 0;
1231             }
1232              
1233 2           return res;
1234             }
1235              
1236             /**
1237             * NI_aggregate(): aggregate two IP address ranges into new object.
1238             * @ipo1: first Net::IP::XS object.
1239             * @ipo2: second Net::IP::XS object.
1240             */
1241             SV *
1242 4           NI_aggregate(SV *ipo1, SV *ipo2)
1243             {
1244             int version;
1245             int res;
1246             char buf[90];
1247             HV *stash;
1248             HV *hash;
1249             SV *ref;
1250              
1251 4           switch ((version = NI_hv_get_iv(ipo1, "ipversion", 9))) {
1252 1           case 4: res = NI_aggregate_ipv4(ipo1, ipo2, buf); break;
1253 2           case 6: res = NI_aggregate_ipv6(ipo1, ipo2, buf); break;
1254 1           default: res = 0;
1255             }
1256              
1257 4 100         if (!res) {
1258 2           return NULL;
1259             }
1260              
1261 2           hash = newHV();
1262 2           ref = newRV_noinc((SV*) hash);
1263 2           stash = gv_stashpv("Net::IP::XS", 1);
1264 2           sv_bless(ref, stash);
1265 2           res = NI_set(ref, buf, version);
1266 2 50         if (!res) {
1267 0           return NULL;
1268             }
1269              
1270 4           return ref;
1271             }
1272              
1273             /**
1274             * NI_overlaps_ipv4(): check if two address ranges overlap.
1275             * @ipo1: first Net::IP::XS object.
1276             * @ipo2: second Net::IP::XS object.
1277             * @buf: result buffer.
1278             */
1279             int
1280 5           NI_overlaps_ipv4(SV *ipo1, SV *ipo2, int *buf)
1281             {
1282             unsigned long b1;
1283             unsigned long b2;
1284             unsigned long e1;
1285             unsigned long e2;
1286              
1287 5           b1 = NI_hv_get_uv(ipo1, "xs_v4_ip0", 9);
1288 5           e1 = NI_hv_get_uv(ipo1, "xs_v4_ip1", 9);
1289 5           b2 = NI_hv_get_uv(ipo2, "xs_v4_ip0", 9);
1290 5           e2 = NI_hv_get_uv(ipo2, "xs_v4_ip1", 9);
1291              
1292 5           NI_ip_is_overlap_ipv4(b1, e1, b2, e2, buf);
1293              
1294 5           return 1;
1295             }
1296              
1297             /**
1298             * NI_overlaps_ipv6(): check if two address ranges overlap.
1299             * @ipo1: first Net::IP::XS object.
1300             * @ipo2: second Net::IP::XS object.
1301             * @buf: result buffer.
1302             */
1303             int
1304 5           NI_overlaps_ipv6(SV *ipo1, SV *ipo2, int *buf)
1305             {
1306             n128_t b1;
1307             n128_t e1;
1308             n128_t b2;
1309             n128_t e2;
1310              
1311 5 50         if (!NI_get_n128s(ipo1, &b1, &e1)) {
1312 0           return 0;
1313             }
1314 5 50         if (!NI_get_n128s(ipo2, &b2, &e2)) {
1315 0           return 0;
1316             }
1317              
1318 5           NI_ip_is_overlap_ipv6(&b1, &e1, &b2, &e2, buf);
1319              
1320 5           return 1;
1321             }
1322              
1323             /**
1324             * NI_overlaps(): check if two address ranges overlap.
1325             * @ipo1: first Net::IP::XS object.
1326             * @ipo2: second Net::IP::XS object.
1327             * @buf: result buffer.
1328             *
1329             * See NI_ip_is_overlap().
1330             */
1331             int
1332 11           NI_overlaps(SV *ipo1, SV* ipo2, int *buf)
1333             {
1334 11           switch (NI_hv_get_iv(ipo1, "ipversion", 9)) {
1335 5           case 4: return NI_overlaps_ipv4(ipo1, ipo2, buf);
1336 5           case 6: return NI_overlaps_ipv6(ipo1, ipo2, buf);
1337 1           default: return 0;
1338             }
1339             }
1340              
1341             /**
1342             * NI_ip_add_num_ipv4(): add integer to object, get new range as string.
1343             * @ipo: Net::IP::XS object.
1344             * @num: integer to add to object.
1345             * @buf: range buffer.
1346             */
1347             int
1348 434           NI_ip_add_num_ipv4(SV *ipo, unsigned long num, char *buf)
1349             {
1350             unsigned long begin;
1351             unsigned long end;
1352             int len;
1353              
1354 434           begin = NI_hv_get_uv(ipo, "xs_v4_ip0", 9);
1355 434           end = NI_hv_get_uv(ipo, "xs_v4_ip1", 9);
1356              
1357 434 100         if ((0xFFFFFFFF - num) < begin) {
1358 1           return 0;
1359             }
1360 433 100         if ((begin + num) > end) {
1361 2           return 0;
1362             }
1363              
1364 431           begin += num;
1365 431           NI_ip_inttoip_ipv4(begin, buf);
1366 431           len = strlen(buf);
1367 431           sprintf(buf + len, " - ");
1368 431           NI_ip_inttoip_ipv4(end, buf + len + 3);
1369              
1370 431           return 1;
1371             }
1372              
1373             /**
1374             * NI_ip_add_num_ipv6(): add integer to object, get new range as string.
1375             * @ipo: Net::IP::XS object.
1376             * @num: integer to add to object.
1377             * @buf: range buffer.
1378             */
1379             int
1380 346           NI_ip_add_num_ipv6(SV *ipo, n128_t *num, char *buf)
1381             {
1382             n128_t begin;
1383             n128_t end;
1384             int len;
1385             int res;
1386              
1387 346 50         if (!NI_get_n128s(ipo, &begin, &end)) {
1388 0           return 0;
1389             }
1390              
1391 346           res = n128_add(num, &begin);
1392 346 50         if (!res) {
1393 0           return 0;
1394             }
1395 346 50         if ( (n128_scan1(num) == INT_MAX)
1396 346 100         || (n128_cmp(num, &begin) <= 0)
1397 345 100         || (n128_cmp(num, &end) > 0)) {
1398 3           return 0;
1399             }
1400              
1401 343           NI_ip_inttoip_n128(num, buf);
1402 343           len = strlen(buf);
1403 343           sprintf(buf + len, " - ");
1404 343           NI_ip_inttoip_n128(&end, buf + len + 3);
1405              
1406 346           return 1;
1407             }
1408              
1409             /**
1410             * NI_ip_add_num(): add integer to object and get new object.
1411             * @ipo: Net::IP::XS object.
1412             * @num: integer to add to object (as a string).
1413             */
1414             SV *
1415 785           NI_ip_add_num(SV *ipo, const char *num)
1416             {
1417             int version;
1418             unsigned long num_ulong;
1419             char *endptr;
1420             n128_t num_n128;
1421             char buf[(2 * (MAX_IPV6_STR_LEN - 1)) + 4];
1422             int res;
1423             HV *stash;
1424             HV *hash;
1425             SV *ref;
1426             int size;
1427              
1428 785           version = NI_hv_get_iv(ipo, "ipversion", 9);
1429              
1430 785 100         if (version == 4) {
1431 436           endptr = NULL;
1432 436           num_ulong = strtoul(num, &endptr, 10);
1433 436 100         if (STRTOUL_FAILED(num_ulong, num, endptr)) {
    50          
    50          
    50          
    0          
1434 2           return 0;
1435             }
1436 434 50         if (num_ulong > 0xFFFFFFFF) {
1437 0           return 0;
1438             }
1439 434           res = NI_ip_add_num_ipv4(ipo, num_ulong, buf);
1440 434 100         if (!res) {
1441 3           return 0;
1442             }
1443 349 50         } else if (version == 6) {
1444 349           res = n128_set_str_decimal(&num_n128, num, strlen(num));
1445 349 100         if (!res) {
1446 3           return 0;
1447             }
1448              
1449 346           res = NI_ip_add_num_ipv6(ipo, &num_n128, buf);
1450 346 100         if (!res) {
1451 3           return 0;
1452             }
1453             } else {
1454 0           return 0;
1455             }
1456              
1457 774           hash = newHV();
1458 774           ref = newRV_noinc((SV*) hash);
1459 774           stash = gv_stashpv("Net::IP::XS", 1);
1460 774           sv_bless(ref, stash);
1461 774           res = NI_set(ref, buf, version);
1462 774 50         if (!res) {
1463 0           return NULL;
1464             }
1465              
1466 785           return ref;
1467             }
1468              
1469             #ifdef __cplusplus
1470             }
1471             #endif