File Coverage

object.c
Criterion Covered Total %
statement 485 551 88.0
branch 187 252 74.2
condition n/a
subroutine n/a
pod n/a
total 672 803 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-2023 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 7           mybuf[0] = '\0';
476              
477 7           is_prefix = NI_hv_get_iv(ipo, "is_prefix", 9);
478              
479 7 100         if (is_prefix) {
480 3           res = NI_short(ipo, mybuf);
481 3 100         if (!res) {
482 1           return 0;
483             }
484 2           prefixlen = NI_hv_get_iv(ipo, "prefixlen", 9);
485 2           snprintf(buf, maxlen, "%s/%d", mybuf, prefixlen);
486             } else {
487 4           first_ip = NI_hv_get_pv(ipo, "ip", 2);
488 4 100         if (!first_ip) {
489 1           return 0;
490             }
491              
492 3           NI_last_ip(ipo, mybuf, MAX_IPV6_STR_LEN);
493 3           second_ip = NI_hv_get_pv(ipo, "last_ip", 7);
494 3 50         if (!second_ip) {
495 0           return 0;
496             }
497              
498 3           snprintf(buf, maxlen, "%s - %s", first_ip, second_ip);
499             }
500              
501 7           return 1;
502             }
503              
504             /**
505             * NI_size_str_ipv4(): get size of IPv4 object as a string.
506             * @ip: Net::IP::XS object.
507             * @buf: size buffer.
508             */
509             int
510 9           NI_size_str_ipv4(SV *ipo, char *buf)
511             {
512             unsigned long begin;
513             unsigned long end;
514              
515 9           begin = NI_hv_get_uv(ipo, "xs_v4_ip0", 9);
516 9           end = NI_hv_get_uv(ipo, "xs_v4_ip1", 9);
517              
518 9 100         if ((begin == 0) && (end == 0xFFFFFFFF)) {
    100          
519 3           sprintf(buf, "4294967296");
520             } else {
521 6           sprintf(buf, "%lu", end - begin + 1);
522             }
523              
524 9           return 1;
525             }
526              
527             /**
528             * NI_size_str_ipv6(): get size of IPv6 object as a string.
529             * @ip: Net::IP::XS object.
530             * @buf: size buffer.
531             */
532             int
533 8           NI_size_str_ipv6(SV *ipo, char *buf)
534             {
535             n128_t begin;
536             n128_t end;
537             int res;
538              
539 8           res = NI_get_n128s(ipo, &begin, &end);
540 8 50         if (!res) {
541 0           return 0;
542             }
543              
544 8 50         if ( n128_scan1(&begin) == INT_MAX
545 8 100         && n128_scan0(&end) == INT_MAX) {
546 7           sprintf(buf, "340282366920938463463374607431768211456");
547 7           return 1;
548             }
549              
550 1           n128_sub(&end, &begin);
551 1           n128_add_ui(&end, 1);
552 1           n128_print_dec(&end, buf);
553              
554 8           return 1;
555             }
556              
557             /**
558             * NI_size_str(): get size of Net::IP::XS object as a string.
559             * @ip: Net::IP::XS object.
560             * @buf: size buffer.
561             *
562             * See NI_size_str_ipv4() and NI_size_str_ipv6().
563             */
564             int
565 19           NI_size_str(SV *ipo, char *size)
566             {
567 19           switch (NI_hv_get_iv(ipo, "ipversion", 9)) {
568 9           case 4: return NI_size_str_ipv4(ipo, size);
569 8           case 6: return NI_size_str_ipv6(ipo, size);
570 2           default: return 0;
571             }
572             }
573              
574             /**
575             * NI_intip_str_ipv4(): get first IP address as an integer string.
576             * @ip: Net::IP::XS object.
577             * @buf: integer string buffer.
578             */
579             int
580 9           NI_intip_str_ipv4(SV *ipo, char *buf)
581             {
582 9           sprintf(buf, "%lu", (unsigned long) NI_hv_get_uv(ipo, "xs_v4_ip0", 9));
583              
584 9           return 1;
585             }
586              
587             /**
588             * NI_intip_str_ipv6(): get first IP address as an integer string.
589             * @ip: Net::IP::XS object.
590             * @buf: integer string buffer.
591             */
592             int
593 7           NI_intip_str_ipv6(SV *ipo, char *buf)
594             {
595             n128_t begin;
596              
597 7 50         if (!NI_get_begin_n128(ipo, &begin)) {
598 0           return 0;
599             }
600              
601 7           n128_print_dec(&begin, buf);
602              
603 7           return 1;
604             }
605              
606             /**
607             * NI_intip_str(): get first IP address as an integer string.
608             * @ip: Net::IP::XS object.
609             * @buf: integer string buffer.
610             * @maxlen: maximum capacity of buffer.
611             */
612             int
613 19           NI_intip_str(SV *ipo, char *buf, int maxlen)
614             {
615             const char *intformat;
616             int res;
617              
618 19 100         if ((intformat = NI_hv_get_pv(ipo, "intformat", 9))) {
619 1           snprintf(buf, maxlen, "%s", intformat);
620 1           return 1;
621             }
622              
623 18           switch (NI_hv_get_iv(ipo, "ipversion", 9)) {
624 9           case 4: res = NI_intip_str_ipv4(ipo, buf); break;
625 7           case 6: res = NI_intip_str_ipv6(ipo, buf); break;
626 2           default: res = 0;
627             }
628              
629 18 100         if (res) {
630 16           HV_MY_STORE_PV(ipo, "intformat", 9, buf, strlen(buf));
631             }
632              
633 18           return res;
634             }
635              
636             /**
637             * NI_hexip_ipv4(): get first IP address as a hex string.
638             * @ip: Net::IP::XS object.
639             * @buf: hex string buffer.
640             *
641             * The string has '0x' prefixed to it.
642             */
643             int
644 2           NI_hexip_ipv4(SV *ipo, char *buf)
645             {
646 2           sprintf(buf, "0x%lx", (unsigned long) NI_hv_get_uv(ipo, "xs_v4_ip0", 9));
647              
648 2           return 1;
649             }
650              
651             /**
652             * NI_hexip_ipv6(): get first IP address as a hex string.
653             * @ip: Net::IP::XS object.
654             * @buf: hex string buffer.
655             *
656             * The string has '0x' prefixed to it.
657             */
658             int
659 2           NI_hexip_ipv6(SV *ipo, char *hexip)
660             {
661             n128_t begin;
662              
663 2 50         if (!NI_get_begin_n128(ipo, &begin)) {
664 0           return 0;
665             }
666              
667 2           n128_print_hex(&begin, hexip);
668              
669 2           return 1;
670             }
671              
672             /**
673             * NI_hexip(): get first IP address as a hex string.
674             * @ip: Net::IP::XS object.
675             * @buf: hex string buffer.
676             * @maxlen: maximum capacity of buffer.
677             *
678             * See NI_hexip_ipv4() and NI_hexip_ipv6().
679             */
680             int
681 7           NI_hexip(SV *ipo, char *buf, int maxlen)
682             {
683             const char *hexformat;
684             int res;
685              
686 7 100         if ((hexformat = NI_hv_get_pv(ipo, "hexformat", 9))) {
687 1           snprintf(buf, maxlen, "%s", hexformat);
688 1           return 1;
689             }
690              
691 6           switch (NI_hv_get_iv(ipo, "ipversion", 9)) {
692 2           case 4: res = NI_hexip_ipv4(ipo, buf); break;
693 2           case 6: res = NI_hexip_ipv6(ipo, buf); break;
694 2           default: res = 0;
695             }
696              
697 6 100         if (res) {
698 4           HV_MY_STORE_PV(ipo, "hexformat", 9, buf, strlen(buf));
699             }
700              
701 6           return res;
702             }
703              
704             /**
705             * NI_hexmask(): return network mask as a hex string.
706             * @ip: Net::IP::XS object.
707             * @buf: hex string buffer.
708             * @maxlen: maximum capacity of buffer.
709             */
710             int
711 7           NI_hexmask(SV *ipo, char *buf, int maxlen)
712             {
713             const char *binmask;
714             const char *hexmask;
715             n128_t dec;
716              
717 7 100         if ((hexmask = NI_hv_get_pv(ipo, "hexmask", 7))) {
718 1           snprintf(buf, maxlen, "%s", hexmask);
719 1           return 1;
720             }
721              
722             /* Net::IP continues with the ip_bintoint call regardless of
723             * whether binmask is defined, but that won't produce reasonable
724             * output anyway, so will return undef instead. */
725              
726 6 100         HV_PV_GET_OR_RETURN(binmask, ipo, "binmask", 7);
727              
728 5           n128_set_str_binary(&dec, binmask, strlen(binmask));
729 5           n128_print_hex(&dec, buf);
730 5           HV_MY_STORE_PV(ipo, "hexmask", 7, buf, strlen(buf));
731              
732 7           return 1;
733             }
734              
735             /**
736             * NI_prefix(): return range in prefix format.
737             * @ipo: Net::IP::XS object.
738             * @buf: prefix buffer.
739             * @maxlen: maximum capacity of buffer.
740             *
741             * Sets Error and Errno in the object if the object does not represent
742             * a single prefix.
743             */
744             int
745 8           NI_prefix(SV *ipo, char *buf, int maxlen)
746             {
747             const char *ip;
748             const char *prefix;
749             int is_prefix;
750             int prefixlen;
751              
752 8           ip = NI_hv_get_pv(ipo, "ip", 2);
753 8 100         if (!ip) {
754 1           ip = "";
755             }
756              
757 8           is_prefix = NI_hv_get_iv(ipo, "is_prefix", 9);
758 8 100         if (!is_prefix) {
759 1           NI_object_set_Error_Errno(ipo, 209, "IP range %s is not a Prefix.",
760             ip);
761 1           return 0;
762             }
763              
764 7 100         if ((prefix = NI_hv_get_pv(ipo, "prefix", 6))) {
765 1           snprintf(buf, maxlen, "%s", prefix);
766 1           return 1;
767             }
768              
769 6           prefixlen = NI_hv_get_iv(ipo, "prefixlen", 9);
770 6 100         if (prefixlen == -1) {
771 1           return 0;
772             }
773 5           snprintf(buf, maxlen, "%s/%d", ip, prefixlen);
774 5           HV_MY_STORE_PV(ipo, "prefix", 6, buf, 0);
775              
776 5           return 1;
777             }
778              
779             /**
780             * NI_mask(): return the IP address mask in IP address format.
781             * @ipo: Net::IP::XS object.
782             * @buf: mask buffer.
783             * @maxlen: maximum capacity of buffer.
784             */
785             int
786 9           NI_mask(SV *ipo, char *buf, int maxlen)
787             {
788             const char *mask;
789             const char *binmask;
790             const char *ip;
791             int is_prefix;
792             int version;
793             int res;
794              
795 9           is_prefix = NI_hv_get_iv(ipo, "is_prefix", 9);
796 9 100         if (!is_prefix) {
797 2           ip = NI_hv_get_pv(ipo, "ip", 2);
798 2 100         if (!ip) {
799 1           ip = "";
800             }
801              
802 2           NI_object_set_Error_Errno(ipo, 209, "IP range %s is not a Prefix.",
803             ip);
804 2           return 0;
805             }
806              
807 7 100         if ((mask = NI_hv_get_pv(ipo, "mask", 4))) {
808 1           snprintf(buf, maxlen, "%s", mask);
809 1           return 1;
810             }
811              
812 6           binmask = NI_hv_get_pv(ipo, "binmask", 7);
813 6 100         if (!binmask) {
814 1           binmask = "";
815             }
816              
817 6           version = NI_hv_get_iv(ipo, "ipversion", 9);
818              
819 6           res = NI_ip_bintoip(binmask, version, buf);
820 6 100         if (!res) {
821 1           NI_copy_Error_Errno(ipo);
822 1           return 0;
823             }
824              
825 5           HV_MY_STORE_PV(ipo, "mask", 4, buf, 0);
826              
827 5           return 1;
828             }
829              
830             /**
831             * NI_iptype(): get the type of the first IP address in the object.
832             * @ipo: Net::IP::XS object.
833             * @buf: type buffer.
834             * @maxlen: maximum capacity of buffer.
835             *
836             * See NI_ip_iptype().
837             */
838             int
839 7           NI_iptype(SV *ipo, char *buf, int maxlen)
840             {
841             const char *binip;
842             const char *iptype;
843             int version;
844             int res;
845              
846 7 100         if ((iptype = NI_hv_get_pv(ipo, "iptype", 6))) {
847 1           snprintf(buf, maxlen, "%s", iptype);
848 1           return 1;
849             }
850              
851 6           binip = NI_hv_get_pv(ipo, "binip", 5);
852 6 100         if (!binip) {
853 1           binip = "";
854             }
855              
856 6           version = NI_hv_get_iv(ipo, "ipversion", 9);
857              
858 6           res = NI_ip_iptype(binip, version, buf);
859 6 100         if (!res) {
860 2           NI_copy_Error_Errno(ipo);
861 2           return 0;
862             }
863              
864 4           HV_MY_STORE_PV(ipo, "iptype", 6, buf, 0);
865              
866 4           return 1;
867             }
868              
869             /**
870             * NI_reverse_ip(): get reverse domain for the first address of an object.
871             * @ipo: Net::IP::XS object.
872             * @buf: reverse domain buffer.
873             *
874             * See NI_ip_reverse().
875             */
876             int
877 6           NI_reverse_ip(SV *ipo, char *buf)
878             {
879             const char *ip;
880             int prefixlen;
881             int version;
882             int res;
883              
884 6           ip = NI_hv_get_pv(ipo, "ip", 2);
885 6 100         if (!ip) {
886 1           ip = "";
887             }
888              
889 6 100         if (!NI_hv_get_iv(ipo, "is_prefix", 9)) {
890 1           NI_object_set_Error_Errno(ipo, 209, "IP range %s is not a Prefix.",
891             ip);
892 1           return 0;
893             }
894              
895 5           prefixlen = NI_hv_get_iv(ipo, "prefixlen", 9);
896 5           version = NI_hv_get_iv(ipo, "ipversion", 9);
897              
898 5           res = NI_ip_reverse(ip, prefixlen, version, buf);
899              
900 5 100         if (!res) {
901 1           NI_copy_Error_Errno(ipo);
902 1           return 0;
903             }
904              
905 4           return 1;
906             }
907              
908             /**
909             * NI_last_bin(): get the last IP address of a range as a bitstring.
910             * @ipo: Net::IP::XS object.
911             * @buf: bitstring buffer.
912             * @maxlen: maximum capacity of buffer.
913             */
914             int
915 13           NI_last_bin(SV *ipo, char *buf, int maxlen)
916             {
917             const char *last_bin;
918             const char *binip;
919             const char *last_ip;
920             int version;
921             int is_prefix;
922             int prefixlen;
923             int res;
924              
925 13 100         if ((last_bin = NI_hv_get_pv(ipo, "last_bin", 8))) {
926 8           snprintf(buf, maxlen, "%s", last_bin);
927 8           return 1;
928             }
929              
930 5           is_prefix = NI_hv_get_iv(ipo, "is_prefix", 9);
931 5           version = NI_hv_get_iv(ipo, "ipversion", 9);
932              
933 5 100         if (is_prefix) {
934 2           binip = NI_hv_get_pv(ipo, "binip", 5);
935 2 100         if (!binip) {
936 1           return 0;
937             }
938 1           prefixlen = NI_hv_get_iv(ipo, "prefixlen", 9);
939 1           res = NI_ip_last_address_bin(binip, prefixlen, version, buf);
940             } else {
941 3           last_ip = NI_hv_get_pv(ipo, "last_ip", 7);
942 3 100         if (!last_ip) {
943 1           return 0;
944             }
945 2           res = NI_ip_iptobin(last_ip, version, buf);
946             }
947              
948 3 100         if (!res) {
949 1           NI_copy_Error_Errno(ipo);
950 1           return 0;
951             }
952              
953 2           buf[NI_iplengths(version)] = '\0';
954              
955 2           HV_MY_STORE_PV(ipo, "last_bin", 8, buf, 0);
956              
957 2           return 1;
958             }
959              
960             /**
961             * NI_last_int_str_ipv4(): get last IP address of a range as an integer string.
962             * @ipo: Net::IP::XS object.
963             * @buf: integer string buffer.
964             */
965 7           int NI_last_int_str_ipv4(SV *ipo, char *buf)
966             {
967             unsigned long end;
968              
969 7           end = NI_hv_get_uv(ipo, "xs_v4_ip1", 9);
970 7           sprintf(buf, "%lu", end);
971              
972 7           return 1;
973             }
974              
975             /**
976             * NI_last_int_str_ipv6(): get last IP address of a range as an integer string.
977             * @ipo: Net::IP::XS object.
978             * @buf: integer string buffer.
979             */
980 8           int NI_last_int_str_ipv6(SV *ipo, char *buf)
981             {
982             n128_t end;
983              
984 8 50         if (!NI_get_end_n128(ipo, &end)) {
985 0           return 0;
986             }
987              
988 8           n128_print_dec(&end, buf);
989              
990 8           return 1;
991             }
992              
993             /**
994             * NI_last_int_str(): get last IP address of a range as an integer string.
995             * @ipo: Net::IP::XS object.
996             * @buf: integer string buffer.
997             * @maxlen: maximum capacity of buffer.
998             */
999             int
1000 18           NI_last_int_str(SV *ipo, char *buf, int maxlen)
1001             {
1002             const char *last_int;
1003             int res;
1004              
1005 18 100         if ((last_int = NI_hv_get_pv(ipo, "last_int", 8))) {
1006 1           snprintf(buf, maxlen, "%s", last_int);
1007 1           return 1;
1008             }
1009              
1010 17           switch (NI_hv_get_iv(ipo, "ipversion", 9)) {
1011 7           case 4: res = NI_last_int_str_ipv4(ipo, buf); break;
1012 8           case 6: res = NI_last_int_str_ipv6(ipo, buf); break;
1013 2           default: res = 0;
1014             }
1015              
1016 17 100         if (res) {
1017 15           HV_MY_STORE_PV(ipo, "last_int", 8, buf, 0);
1018             }
1019              
1020 17           return res;
1021             }
1022              
1023             /**
1024             * NI_bincomp(): compare first IP addresses of two ranges.
1025             * @ipo1: first Net::IP::XS object.
1026             * @op: the comparator as a string.
1027             * @ipo2: second Net::IP::XS object.
1028             * @buf: result buffer.
1029             *
1030             * See NI_ip_bincomp().
1031             */
1032             int
1033 4           NI_bincomp(SV *ipo1, const char *op, SV *ipo2, int *resbuf)
1034             {
1035             const char *binip1;
1036             const char *binip2;
1037             int res;
1038              
1039 4           binip1 = NI_hv_get_pv(ipo1, "binip", 5);
1040 4 100         if (!binip1) {
1041 1           binip1 = "";
1042             }
1043              
1044 4           binip2 = NI_hv_get_pv(ipo2, "binip", 5);
1045 4 100         if (!binip2) {
1046 1           binip2 = "";
1047             }
1048              
1049 4           res = NI_ip_bincomp(binip1, op, binip2, resbuf);
1050 4 100         if (!res) {
1051 1           NI_copy_Error_Errno(ipo1);
1052 1           return 0;
1053             }
1054              
1055 3           return 1;
1056             }
1057              
1058             /**
1059             * NI_binadd(): get new object from the sum of two IP addresses.
1060             * @ipo1: first Net::IP::XS object.
1061             * @ipo2: second Net::IP::XS object.
1062             */
1063             SV *
1064 4           NI_binadd(SV *ipo1, SV *ipo2)
1065             {
1066             const char *binip1;
1067             const char *binip2;
1068             int version;
1069             char binbuf[130];
1070             char buf[45];
1071             int res;
1072             HV *stash;
1073             HV *hash;
1074             SV *ref;
1075             int iplen;
1076              
1077 4           binip1 = NI_hv_get_pv(ipo1, "binip", 5);
1078 4 100         if (!binip1) {
1079 1           binip1 = "";
1080             }
1081              
1082 4           binip2 = NI_hv_get_pv(ipo2, "binip", 5);
1083 4 100         if (!binip2) {
1084 1           binip2 = "";
1085             }
1086              
1087 4           res = NI_ip_binadd(binip1, binip2, binbuf, IPV6_BITSTR_LEN);
1088 4 100         if (!res) {
1089 1           NI_copy_Error_Errno(ipo1);
1090 1           return NULL;
1091             }
1092              
1093 3           version = NI_hv_get_iv(ipo1, "ipversion", 9);
1094 3           iplen = NI_iplengths(version);
1095 3           binbuf[iplen] = '\0';
1096 3           buf[0] = '\0';
1097              
1098 3           res = NI_ip_bintoip(binbuf, version, buf);
1099 3 50         if (!res) {
1100 0           return NULL;
1101             }
1102              
1103 3           hash = newHV();
1104 3           ref = newRV_noinc((SV*) hash);
1105 3           stash = gv_stashpv("Net::IP::XS", 1);
1106 3           sv_bless(ref, stash);
1107 3           res = NI_set(ref, buf, version);
1108 3 50         if (!res) {
1109 0           return NULL;
1110             }
1111              
1112 4           return ref;
1113             }
1114              
1115             /**
1116             * NI_aggregate_ipv4(): aggregate two IP address ranges into new object.
1117             * @ipo1: first Net::IP::XS object.
1118             * @ipo2: second Net::IP::XS object.
1119             */
1120             int
1121 1           NI_aggregate_ipv4(SV *ipo1, SV *ipo2, char *buf)
1122             {
1123             unsigned long b1;
1124             unsigned long b2;
1125             unsigned long e1;
1126             unsigned long e2;
1127             const char *ip1;
1128             const char *ip2;
1129             int res;
1130              
1131 1           b1 = NI_hv_get_uv(ipo1, "xs_v4_ip0", 9);
1132 1           e1 = NI_hv_get_uv(ipo1, "xs_v4_ip1", 9);
1133 1           b2 = NI_hv_get_uv(ipo2, "xs_v4_ip0", 9);
1134 1           e2 = NI_hv_get_uv(ipo2, "xs_v4_ip1", 9);
1135              
1136 1           res = NI_ip_aggregate_ipv4(b1, e1, b2, e2, 4, buf);
1137 1 50         if (res == 0) {
1138 0           NI_copy_Error_Errno(ipo1);
1139 0           return 0;
1140             }
1141 1 50         if (res == 160) {
1142 0           ip1 = NI_hv_get_pv(ipo1, "last_ip", 7);
1143 0 0         if (!ip1) {
1144 0           ip1 = "";
1145             }
1146 0           ip2 = NI_hv_get_pv(ipo2, "ip", 2);
1147 0 0         if (!ip2) {
1148 0           ip2 = "";
1149             }
1150 0           NI_set_Error_Errno(160, "Ranges not contiguous - %s - %s",
1151             ip1, ip2);
1152 0           NI_copy_Error_Errno(ipo1);
1153 0           return 0;
1154             }
1155 1 50         if (res == 161) {
1156 0           ip1 = NI_hv_get_pv(ipo1, "ip", 7);
1157 0 0         if (!ip1) {
1158 0           ip1 = "";
1159             }
1160 0           ip2 = NI_hv_get_pv(ipo2, "last_ip", 2);
1161 0 0         if (!ip2) {
1162 0           ip2 = "";
1163             }
1164 0           NI_set_Error_Errno(161, "%s - %s is not a single prefix",
1165             ip1, ip2);
1166 0           NI_copy_Error_Errno(ipo1);
1167 0           return 0;
1168             }
1169              
1170 1           return 1;
1171             }
1172              
1173             /**
1174             * NI_aggregate_ipv6(): aggregate two IP address ranges into new object.
1175             * @ipo1: first Net::IP::XS object.
1176             * @ipo2: second Net::IP::XS object.
1177             */
1178             int
1179 2           NI_aggregate_ipv6(SV *ipo1, SV *ipo2, char *buf)
1180             {
1181             n128_t b1;
1182             n128_t e1;
1183             n128_t b2;
1184             n128_t e2;
1185             int res;
1186             const char *ip1;
1187             const char *ip2;
1188              
1189 2 50         if (!NI_get_n128s(ipo1, &b1, &e1)) {
1190 0           return 0;
1191             }
1192 2 50         if (!NI_get_n128s(ipo2, &b2, &e2)) {
1193 0           return 0;
1194             }
1195              
1196 2           res = NI_ip_aggregate_ipv6(&b1, &e1, &b2, &e2, 6, buf);
1197              
1198 2 50         if (res == 0) {
1199 0           NI_copy_Error_Errno(ipo1);
1200 0           return 0;
1201             }
1202 2 100         if (res == 160) {
1203 1           ip1 = NI_hv_get_pv(ipo1, "last_ip", 7);
1204 1 50         if (!ip1) {
1205 0           ip1 = "";
1206             }
1207 1           ip2 = NI_hv_get_pv(ipo2, "ip", 2);
1208 1 50         if (!ip2) {
1209 0           ip2 = "";
1210             }
1211 1           NI_set_Error_Errno(160, "Ranges not contiguous - %s - %s",
1212             ip1, ip2);
1213 1           NI_copy_Error_Errno(ipo1);
1214 1           return 0;
1215             }
1216 1 50         if (res == 161) {
1217 0           ip1 = NI_hv_get_pv(ipo1, "ip", 7);
1218 0 0         if (!ip1) {
1219 0           ip1 = "";
1220             }
1221 0           ip2 = NI_hv_get_pv(ipo2, "last_ip", 2);
1222 0 0         if (!ip2) {
1223 0           ip2 = "";
1224             }
1225 0           NI_set_Error_Errno(161, "%s - %s is not a single prefix",
1226             ip1, ip2);
1227 0           NI_copy_Error_Errno(ipo1);
1228 0           return 0;
1229             }
1230              
1231 2           return res;
1232             }
1233              
1234             /**
1235             * NI_aggregate(): aggregate two IP address ranges into new object.
1236             * @ipo1: first Net::IP::XS object.
1237             * @ipo2: second Net::IP::XS object.
1238             */
1239             SV *
1240 4           NI_aggregate(SV *ipo1, SV *ipo2)
1241             {
1242             int version;
1243             int res;
1244             char buf[90];
1245             HV *stash;
1246             HV *hash;
1247             SV *ref;
1248              
1249 4           switch ((version = NI_hv_get_iv(ipo1, "ipversion", 9))) {
1250 1           case 4: res = NI_aggregate_ipv4(ipo1, ipo2, buf); break;
1251 2           case 6: res = NI_aggregate_ipv6(ipo1, ipo2, buf); break;
1252 1           default: res = 0;
1253             }
1254              
1255 4 100         if (!res) {
1256 2           return NULL;
1257             }
1258              
1259 2           hash = newHV();
1260 2           ref = newRV_noinc((SV*) hash);
1261 2           stash = gv_stashpv("Net::IP::XS", 1);
1262 2           sv_bless(ref, stash);
1263 2           res = NI_set(ref, buf, version);
1264 2 50         if (!res) {
1265 0           return NULL;
1266             }
1267              
1268 4           return ref;
1269             }
1270              
1271             /**
1272             * NI_overlaps_ipv4(): check if two address ranges overlap.
1273             * @ipo1: first Net::IP::XS object.
1274             * @ipo2: second Net::IP::XS object.
1275             * @buf: result buffer.
1276             */
1277             int
1278 5           NI_overlaps_ipv4(SV *ipo1, SV *ipo2, int *buf)
1279             {
1280             unsigned long b1;
1281             unsigned long b2;
1282             unsigned long e1;
1283             unsigned long e2;
1284              
1285 5           b1 = NI_hv_get_uv(ipo1, "xs_v4_ip0", 9);
1286 5           e1 = NI_hv_get_uv(ipo1, "xs_v4_ip1", 9);
1287 5           b2 = NI_hv_get_uv(ipo2, "xs_v4_ip0", 9);
1288 5           e2 = NI_hv_get_uv(ipo2, "xs_v4_ip1", 9);
1289              
1290 5           NI_ip_is_overlap_ipv4(b1, e1, b2, e2, buf);
1291              
1292 5           return 1;
1293             }
1294              
1295             /**
1296             * NI_overlaps_ipv6(): check if two address ranges overlap.
1297             * @ipo1: first Net::IP::XS object.
1298             * @ipo2: second Net::IP::XS object.
1299             * @buf: result buffer.
1300             */
1301             int
1302 5           NI_overlaps_ipv6(SV *ipo1, SV *ipo2, int *buf)
1303             {
1304             n128_t b1;
1305             n128_t e1;
1306             n128_t b2;
1307             n128_t e2;
1308              
1309 5 50         if (!NI_get_n128s(ipo1, &b1, &e1)) {
1310 0           return 0;
1311             }
1312 5 50         if (!NI_get_n128s(ipo2, &b2, &e2)) {
1313 0           return 0;
1314             }
1315              
1316 5           NI_ip_is_overlap_ipv6(&b1, &e1, &b2, &e2, buf);
1317              
1318 5           return 1;
1319             }
1320              
1321             /**
1322             * NI_overlaps(): check if two address ranges overlap.
1323             * @ipo1: first Net::IP::XS object.
1324             * @ipo2: second Net::IP::XS object.
1325             * @buf: result buffer.
1326             *
1327             * See NI_ip_is_overlap().
1328             */
1329             int
1330 11           NI_overlaps(SV *ipo1, SV* ipo2, int *buf)
1331             {
1332 11           switch (NI_hv_get_iv(ipo1, "ipversion", 9)) {
1333 5           case 4: return NI_overlaps_ipv4(ipo1, ipo2, buf);
1334 5           case 6: return NI_overlaps_ipv6(ipo1, ipo2, buf);
1335 1           default: return 0;
1336             }
1337             }
1338              
1339             /**
1340             * NI_ip_add_num_ipv4(): add integer to object, get new range as string.
1341             * @ipo: Net::IP::XS object.
1342             * @num: integer to add to object.
1343             * @buf: range buffer.
1344             */
1345             int
1346 434           NI_ip_add_num_ipv4(SV *ipo, unsigned long num, char *buf)
1347             {
1348             unsigned long begin;
1349             unsigned long end;
1350             int len;
1351              
1352 434           begin = NI_hv_get_uv(ipo, "xs_v4_ip0", 9);
1353 434           end = NI_hv_get_uv(ipo, "xs_v4_ip1", 9);
1354              
1355 434 100         if ((0xFFFFFFFF - num) < begin) {
1356 1           return 0;
1357             }
1358 433 100         if ((begin + num) > end) {
1359 2           return 0;
1360             }
1361              
1362 431           begin += num;
1363 431           NI_ip_inttoip_ipv4(begin, buf);
1364 431           len = strlen(buf);
1365 431           sprintf(buf + len, " - ");
1366 431           NI_ip_inttoip_ipv4(end, buf + len + 3);
1367              
1368 431           return 1;
1369             }
1370              
1371             /**
1372             * NI_ip_add_num_ipv6(): add integer to object, get new range as string.
1373             * @ipo: Net::IP::XS object.
1374             * @num: integer to add to object.
1375             * @buf: range buffer.
1376             */
1377             int
1378 346           NI_ip_add_num_ipv6(SV *ipo, n128_t *num, char *buf)
1379             {
1380             n128_t begin;
1381             n128_t end;
1382             int len;
1383             int res;
1384              
1385 346 50         if (!NI_get_n128s(ipo, &begin, &end)) {
1386 0           return 0;
1387             }
1388              
1389 346           res = n128_add(num, &begin);
1390 346 50         if (!res) {
1391 0           return 0;
1392             }
1393 346 50         if ( (n128_scan1(num) == INT_MAX)
1394 346 100         || (n128_cmp(num, &begin) <= 0)
1395 345 100         || (n128_cmp(num, &end) > 0)) {
1396 3           return 0;
1397             }
1398              
1399 343           NI_ip_inttoip_n128(num, buf);
1400 343           len = strlen(buf);
1401 343           sprintf(buf + len, " - ");
1402 343           NI_ip_inttoip_n128(&end, buf + len + 3);
1403              
1404 346           return 1;
1405             }
1406              
1407             /**
1408             * NI_ip_add_num(): add integer to object and get new object.
1409             * @ipo: Net::IP::XS object.
1410             * @num: integer to add to object (as a string).
1411             */
1412             SV *
1413 785           NI_ip_add_num(SV *ipo, const char *num)
1414             {
1415             int version;
1416             unsigned long num_ulong;
1417             char *endptr;
1418             n128_t num_n128;
1419             char buf[(2 * (MAX_IPV6_STR_LEN - 1)) + 4];
1420             int res;
1421             HV *stash;
1422             HV *hash;
1423             SV *ref;
1424             int size;
1425              
1426 785           version = NI_hv_get_iv(ipo, "ipversion", 9);
1427              
1428 785 100         if (version == 4) {
1429 436           endptr = NULL;
1430 436           num_ulong = strtoul(num, &endptr, 10);
1431 436 100         if (STRTOUL_FAILED(num_ulong, num, endptr)) {
    50          
    50          
    50          
    0          
1432 2           return 0;
1433             }
1434 434 50         if (num_ulong > 0xFFFFFFFF) {
1435 0           return 0;
1436             }
1437 434           res = NI_ip_add_num_ipv4(ipo, num_ulong, buf);
1438 434 100         if (!res) {
1439 3           return 0;
1440             }
1441 349 50         } else if (version == 6) {
1442 349           res = n128_set_str_decimal(&num_n128, num, strlen(num));
1443 349 100         if (!res) {
1444 3           return 0;
1445             }
1446              
1447 346           res = NI_ip_add_num_ipv6(ipo, &num_n128, buf);
1448 346 100         if (!res) {
1449 3           return 0;
1450             }
1451             } else {
1452 0           return 0;
1453             }
1454              
1455 774           hash = newHV();
1456 774           ref = newRV_noinc((SV*) hash);
1457 774           stash = gv_stashpv("Net::IP::XS", 1);
1458 774           sv_bless(ref, stash);
1459 774           res = NI_set(ref, buf, version);
1460 774 50         if (!res) {
1461 0           return NULL;
1462             }
1463              
1464 785           return ref;
1465             }
1466              
1467             #ifdef __cplusplus
1468             }
1469             #endif