File Coverage

object.c
Criterion Covered Total %
statement 484 550 88.0
branch 187 252 74.2
condition n/a
subroutine n/a
pod n/a
total 671 802 83.6


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