File Coverage

TIPC.xs
Criterion Covered Total %
statement 105 128 82.0
branch 4 8 50.0
condition n/a
subroutine n/a
pod n/a
total 109 136 80.1


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #include "ppport.h"
6              
7             #include "tipc.h"
8              
9             #ifndef PF_TIPC
10             # ifdef AF_TIPC
11             # define PF_TIPC AF_TIPC
12             # endif
13             #endif
14              
15             /* We toss these around a LOT. Use a typedef, to keep it concise. */
16             typedef struct sockaddr_tipc SAT;
17              
18             /* input-checking for passing a struct sockaddr_tipc from within an SvRV*. */
19 137           SAT *_tipc_sanity_check(SV *rv) {
20             SV *sv;
21 137 50         if(SvTYPE(rv) == SVt_RV)
22 137           sv = SvRV(rv);
23             else
24 0           croak("Sockaddr methods work on blessed references to raw data.");
25 137 50         if(sv_len(sv) != 16)
26 0           croak("Sockaddr method called with non-sockaddr argument! (length is %i)",sv_len(sv));
27             else {
28 137 50         SAT *sat = (void*)SvPV_nolen(sv);
29 137 50         if(sat->family != AF_TIPC)
30 0           croak("Sockaddr family mismatch: not AF_TIPC!");
31 137           return sat;
32             }
33             return NULL;
34             }
35              
36             /* in the following code, internal functions are prefixed with "_tipc_".
37             * Stuff intended for direct user use does not have this prefix. */
38              
39             #include "const-c.inc"
40              
41             MODULE = IO::Socket::TIPC PACKAGE = IO::Socket::TIPC
42              
43             INCLUDE: const-xs.inc
44              
45             MODULE = IO::Socket::TIPC PACKAGE = IO::Socket::TIPC::Sockaddr
46              
47             PROTOTYPES: ENABLE
48              
49             # THE SOCKADDR XS STUFF
50             #
51             # What follows are some accessor functions for the sockaddr_tipc structure.
52             # I could have simply done some pack()/unpack() statements in Perl code, but
53             # that would break horribly if they ever changed the structure, resulting in
54             # size mismatches and such. This way it'll stay valid as long as they leave
55             # a migration path.
56             #
57             # Also note that these routines will break horribly if you call them with a
58             # wrongly sized (clobbered, truncated, whatever) SV. Calling code should be
59             # careful to create the SV with _create(), and never write to it directly.
60             # None of these functions are published directly, though the module's user
61             # may be able to clobber the struct with vec and s/\0/1/ and the like.
62             #
63             # OBJECT CREATION STUFF
64             #
65             # SV *_tipc_create()
66             #
67             # Create a blank buffer of the right length; set family to AF_TIPC, and return
68             # the buffer wrapped up in a scalar.
69              
70             SV *
71             _tipc_create()
72             INIT:
73             SAT sat;
74             SV *sv, *rv;
75             CODE:
76 25           memset(&sat,0,sizeof(sat));
77 25           sat.family = AF_TIPC;
78 25           rv = newSV(0);
79 25           sv = newSVrv(rv,"IO::Socket::TIPC::Sockaddr");
80 25           sv_setpvn(sv, (void*)&sat, sizeof(sat));
81 25           RETVAL = rv;
82             OUTPUT:
83             RETVAL
84              
85             # void _tipc_clear(SV *sv)
86             #
87             # Wipe a buffer clean. Memsets it to 0, then sets the family to AF_TIPC again.
88              
89             void
90             _tipc_clear(sv)
91             SV *sv
92             INIT:
93 0           SAT *sat = _tipc_sanity_check(sv);
94             CODE:
95 0           memset(sat,0,sizeof(SAT));
96 0           sat->family = AF_TIPC;
97             OUTPUT:
98             sv
99              
100             # void _tipc_fill_common(SV *sv, char scope)
101             #
102             # Fill in the fields which are common to all sockaddrs. Turns out there's only
103             # one common field; the scope. This is an enum, use it with constants like
104             # TIPC_NODE_SCOPE.
105             # Perl does some weird (unwanted) conversion on the "char" type; use I8 (8-bit
106             # integer) instead.
107              
108             void
109             _tipc_fill_common(sv, scope)
110             SV *sv
111             I8 scope
112             INIT:
113 25           SAT *sat = _tipc_sanity_check(sv);
114             CODE:
115 25           sat->family = AF_TIPC;
116 25           sat->scope = scope;
117             OUTPUT:
118             sv
119              
120             # void _tipc_fill_id(SV *sv, unsigned int ref, unsigned int node)
121             #
122             # Fill in the fields which are specific to ID sockaddrs. Ref is a 32-bit integer
123             # which is autogenerated by the OS, and unique for every open socket in the
124             # system. Node is the packed TIPC address. tipc_addr can create this from the
125             # components, or see _tipc_fill_id_pieces().
126              
127             void
128             _tipc_fill_id(sv, ref, node)
129             SV *sv
130             unsigned int ref
131             unsigned int node
132             INIT:
133 0           SAT *sat = _tipc_sanity_check(sv);
134             CODE:
135 0           sat->addrtype = TIPC_ADDR_ID;
136 0           sat->addr.id.ref = ref;
137 0           sat->addr.id.node = node;
138             OUTPUT:
139             sv
140              
141             # void _tipc_fill_id_pieces(SV *sv, unsigned int ref, unsigned int zone, unsigned int cluster, unsigned int node)
142             #
143             # Fill in the fields which are specific to ID sockaddrs. Ref is a 32-bit integer
144             # which is autogenerated by the OS, and unique for every open socket in the
145             # system. is the TIPC address portion. These fields get
146             # packed into one 32-bit int with tipc_addr(). See _tipc_fill_id().
147              
148             void
149             _tipc_fill_id_pieces(sv, ref, zone, cluster, node)
150             SV *sv
151             unsigned int ref
152             unsigned int zone
153             unsigned int cluster
154             unsigned int node
155             INIT:
156 6           SAT *sat = _tipc_sanity_check(sv);
157             CODE:
158 6           sat->addrtype = TIPC_ADDR_ID;
159 6           sat->addr.id.ref = ref;
160 6           sat->addr.id.node = tipc_addr(zone, cluster, node);
161             OUTPUT:
162             sv
163              
164             # void _tipc_fill_name(SV *sv, unsigned int type, unsigned int instance, unsigned int domain)
165             #
166             # Fill in the fields which are specific to NAME sockaddrs. {Type,Instance} are
167             # both 32-bit integers, which together specify the "name" of the socket. Domain
168             # specifies where to start from when searching for a name, for connect() and
169             # sendto().
170              
171             void
172             _tipc_fill_name(sv, type, instance, domain)
173             SV *sv
174             unsigned int type
175             unsigned int instance
176             unsigned int domain
177             INIT:
178 13           SAT *sat = _tipc_sanity_check(sv);
179             CODE:
180 13           sat->addrtype = TIPC_ADDR_NAME;
181 13           sat->addr.name.name.type = type;
182 13           sat->addr.name.name.instance = instance;
183 13           sat->addr.name.domain = domain;
184             OUTPUT:
185             sv
186              
187             # void _tipc_fill_nameseq(SV *sv, unsigned int type, unsigned int lower, unsigned int upper)
188             #
189             # Fill in the fields which are specific to NAMESEQ sockaddrs. Type is a 32-bit
190             # integer, specifying the first half of a NAME. Lower and Upper are also 32-bit
191             # integers, which specify a range of Instances, which make up the second half of
192             # the NAME. They go together like {Type,Lower,Upper}, to specify a range of
193             # names to use in multicast communications.
194              
195             void
196             _tipc_fill_nameseq(sv, type, lower, upper)
197             SV *sv
198             unsigned int type
199             unsigned int lower
200             unsigned int upper
201             INIT:
202 6           SAT *sat = _tipc_sanity_check(sv);
203             CODE:
204 6           sat->addrtype = TIPC_ADDR_NAMESEQ;
205 6           sat->addr.nameseq.type = type;
206 6           sat->addr.nameseq.lower = lower;
207 6           sat->addr.nameseq.upper = upper;
208             OUTPUT:
209             sv
210              
211             # void stringify(SV *sv)
212             #
213             # Stringifies the sockaddr, obviously. This is great for user interface stuff
214             # and logfiles, but note that the string it returns is missing some (possibly
215             # useful) portions of the sockaddr_tipc, Scope and Domain for example.
216              
217             SV *
218             stringify(sv)
219             SV *sv
220             INIT:
221             struct node_addr;
222 32           SAT *sat = _tipc_sanity_check(sv);
223             CODE:
224             /* _tipc_sanity_check already checked AF_INET for us. */
225 32           switch(sat->addrtype) {
226             case 0:
227 0           RETVAL = newSVpvf("(uninitialized addrtype)");
228 0           break;
229             case TIPC_ADDR_ID: /* by TIPC address and ref-id */
230 9           RETVAL = newSVpvf("<%u.%u.%u:%u>",tipc_zone(sat->addr.id.node),
231             tipc_cluster(sat->addr.id.node),tipc_node(sat->addr.id.node),
232             sat->addr.id.ref);
233 9           break;
234             case TIPC_ADDR_NAME: /* by name (NOTE: "domain" isn't shown) */
235 15           RETVAL = newSVpvf("{%u, %u}",sat->addr.name.name.type,
236             sat->addr.name.name.instance);
237 15           break;
238             case TIPC_ADDR_NAMESEQ: /* multicast name range */
239 8           RETVAL = newSVpvf("{%u, %u, %u}",sat->addr.nameseq.type,
240             sat->addr.nameseq.lower,sat->addr.nameseq.upper);
241 8           break;
242             default:
243 0           RETVAL = newSVpvf("(invalid addrtype)");
244 0           break;
245             }
246             OUTPUT:
247             RETVAL
248              
249             # lowlevel field-access routines.
250             #
251             # Wrappers for the get/set routines for each field of struct sockaddr_tipc.
252             # sockaddr_tipc.family needs to be readonly, in order for the sanity checks
253             # to pass. So, we don't provide a set_family function. Everything else
254             # is read/writable.
255             #
256             # I wish XS didn't require so much whitespace. These should be made quite a bit
257             # more compact.
258             #
259             # Start with the get_* functions.
260              
261             U16
262             get_family(sv)
263             SV *sv
264             INIT:
265 1           SAT *sat = _tipc_sanity_check(sv);
266             CODE:
267 1           RETVAL = sat->family;
268             OUTPUT:
269             RETVAL
270              
271             U8
272             get_addrtype(sv)
273             SV *sv
274             INIT:
275 5           SAT *sat = _tipc_sanity_check(sv);
276             CODE:
277 5           RETVAL = sat->addrtype;
278             OUTPUT:
279             RETVAL
280              
281             I8
282             get_scope(sv)
283             SV *sv
284             INIT:
285 7           SAT *sat = _tipc_sanity_check(sv);
286             CODE:
287 7           RETVAL = sat->scope;
288             OUTPUT:
289             RETVAL
290              
291             U32
292             get_ref(sv)
293             SV *sv
294             INIT:
295 3           SAT *sat = _tipc_sanity_check(sv);
296             CODE:
297 3           RETVAL = sat->addr.id.ref;
298             OUTPUT:
299             RETVAL
300              
301             U32
302             get_id(sv)
303             SV *sv
304             INIT:
305 0           SAT *sat = _tipc_sanity_check(sv);
306             CODE:
307 0           RETVAL = sat->addr.id.node;
308             OUTPUT:
309             RETVAL
310              
311             U32
312             get_zone(sv)
313             SV *sv
314             INIT:
315 3           SAT *sat = _tipc_sanity_check(sv);
316             CODE:
317 3           RETVAL = tipc_zone(sat->addr.id.node);
318             OUTPUT:
319             RETVAL
320              
321             U32
322             get_cluster(sv)
323             SV *sv
324             INIT:
325 3           SAT *sat = _tipc_sanity_check(sv);
326             CODE:
327 3           RETVAL = tipc_cluster(sat->addr.id.node);
328             OUTPUT:
329             RETVAL
330              
331             U32
332             get_node(sv)
333             SV *sv
334             INIT:
335 3           SAT *sat = _tipc_sanity_check(sv);
336             CODE:
337 3           RETVAL = tipc_node(sat->addr.id.node);
338             OUTPUT:
339             RETVAL
340              
341             U32
342             get_ntype(sv)
343             SV *sv
344             INIT:
345 1           SAT *sat = _tipc_sanity_check(sv);
346             CODE:
347 1           RETVAL = sat->addr.name.name.type;
348             OUTPUT:
349             RETVAL
350              
351             U32
352             get_instance(sv)
353             SV *sv
354             INIT:
355 1           SAT *sat = _tipc_sanity_check(sv);
356             CODE:
357 1           RETVAL = sat->addr.name.name.instance;
358             OUTPUT:
359             RETVAL
360              
361             U32
362             get_domain(sv)
363             SV *sv
364             INIT:
365 6           SAT *sat = _tipc_sanity_check(sv);
366             CODE:
367 6           RETVAL = sat->addr.name.domain;
368             OUTPUT:
369             RETVAL
370              
371             U32
372             get_stype(sv)
373             SV *sv
374             INIT:
375 1           SAT *sat = _tipc_sanity_check(sv);
376             CODE:
377 1           RETVAL = sat->addr.nameseq.type;
378             OUTPUT:
379             RETVAL
380              
381             U32
382             get_lower(sv)
383             SV *sv
384             INIT:
385 1           SAT *sat = _tipc_sanity_check(sv);
386             CODE:
387 1           RETVAL = sat->addr.nameseq.lower;
388             OUTPUT:
389             RETVAL
390              
391             U32
392             get_upper(sv)
393             SV *sv
394             INIT:
395 1           SAT *sat = _tipc_sanity_check(sv);
396             CODE:
397 1           RETVAL = sat->addr.nameseq.upper;
398             OUTPUT:
399             RETVAL
400              
401             # And here are the set_* functions. I hate how big and ugly these are...
402             # XS needs a Class::MethodMaker equivalent.
403             #
404             # NOTE: _tipc_set_id() and _tipc_set_domain() have private prefixes for a good
405             # reason. They are wrapped around in the .pm code so they can take ""
406             # strings.
407              
408             U8
409             set_addrtype(sv,arg)
410             SV *sv
411             U8 arg
412             INIT:
413 0           SAT *sat = _tipc_sanity_check(sv);
414             CODE:
415 0           RETVAL = sat->addrtype = arg;
416             OUTPUT:
417             RETVAL
418              
419             I8
420             set_scope(sv,arg)
421             SV *sv
422             I8 arg
423             INIT:
424 0           SAT *sat = _tipc_sanity_check(sv);
425             CODE:
426 0           RETVAL = sat->scope = arg;
427             OUTPUT:
428             RETVAL
429              
430             U32
431             set_ref(sv,arg)
432             SV *sv
433             U32 arg
434             INIT:
435 1           SAT *sat = _tipc_sanity_check(sv);
436             CODE:
437 1           RETVAL = sat->addr.id.ref = arg;
438             OUTPUT:
439             RETVAL
440              
441             U32
442             _tipc_set_id(sv,arg)
443             SV *sv
444             U32 arg
445             INIT:
446 2           SAT *sat = _tipc_sanity_check(sv);
447             CODE:
448 2           RETVAL = sat->addr.id.node = arg;
449             OUTPUT:
450             RETVAL
451              
452             U32
453             set_zone(sv,arg)
454             SV *sv
455             U32 arg
456             INIT:
457 1           SAT *sat = _tipc_sanity_check(sv);
458             CODE:
459 1           sat->addr.id.node = tipc_addr(arg,tipc_cluster(sat->addr.id.node),tipc_node(sat->addr.id.node));
460 1           RETVAL = arg;
461             OUTPUT:
462             RETVAL
463              
464             U32
465             set_cluster(sv,arg)
466             SV *sv
467             U32 arg
468             INIT:
469 1           SAT *sat = _tipc_sanity_check(sv);
470             CODE:
471 1           sat->addr.id.node = tipc_addr(tipc_zone(sat->addr.id.node),arg,tipc_node(sat->addr.id.node));
472 1           RETVAL = arg;
473             OUTPUT:
474             RETVAL
475              
476             U32
477             set_node(sv,arg)
478             SV *sv
479             U32 arg
480             INIT:
481 1           SAT *sat = _tipc_sanity_check(sv);
482             CODE:
483 1           sat->addr.id.node = tipc_addr(tipc_zone(sat->addr.id.node),tipc_cluster(sat->addr.id.node),arg);
484 1           RETVAL = arg;
485             OUTPUT:
486             RETVAL
487              
488             U32
489             set_ntype(sv,arg)
490             SV *sv
491             U32 arg
492             INIT:
493 1           SAT *sat = _tipc_sanity_check(sv);
494             CODE:
495 1           RETVAL = sat->addr.name.name.type = arg;
496             OUTPUT:
497             RETVAL
498              
499             U32
500             set_instance(sv,arg)
501             SV *sv
502             U32 arg
503             INIT:
504 1           SAT *sat = _tipc_sanity_check(sv);
505             CODE:
506 1           RETVAL = sat->addr.name.name.instance = arg;
507             OUTPUT:
508             RETVAL
509              
510             U32
511             _tipc_set_domain(sv,arg)
512             SV *sv
513             U32 arg
514             INIT:
515 2           SAT *sat = _tipc_sanity_check(sv);
516             CODE:
517 2           RETVAL = sat->addr.name.domain = arg;
518             OUTPUT:
519             RETVAL
520              
521             U32
522             set_stype(sv,arg)
523             SV *sv
524             U32 arg
525             INIT:
526 1           SAT *sat = _tipc_sanity_check(sv);
527             CODE:
528 1           RETVAL = sat->addr.nameseq.type = arg;
529             OUTPUT:
530             RETVAL
531              
532             U32
533             set_lower(sv,arg)
534             SV *sv
535             U32 arg
536             INIT:
537 1           SAT *sat = _tipc_sanity_check(sv);
538             CODE:
539 1           RETVAL = sat->addr.nameseq.lower = arg;
540             OUTPUT:
541             RETVAL
542              
543             U32
544             set_upper(sv,arg)
545             SV *sv
546             U32 arg
547             INIT:
548 1           SAT *sat = _tipc_sanity_check(sv);
549             CODE:
550 1           RETVAL = sat->addr.nameseq.upper = arg;
551             OUTPUT:
552             RETVAL
553              
554             # get_type()/set_type() wrappers to choose nameseq.type versus name.name.type.
555             # These are only here just in case they change the sockaddr_tipc structure so
556             # the two no longer share the same memory location via a union. Pretty
557             # unlikely...
558              
559             U32
560             get_type(sv)
561             SV *sv
562             INIT:
563 4           SAT *sat = _tipc_sanity_check(sv);
564             CODE:
565 4           switch(sat->addrtype) {
566             case TIPC_ADDR_NAME:
567 2           RETVAL = sat->addr.name.name.type;
568 2           break;
569             case TIPC_ADDR_NAMESEQ:
570 2           RETVAL = sat->addr.nameseq.type;
571 2           break;
572             default:
573 0           croak("get_type() called for a typeless sockaddr.");
574             }
575             OUTPUT:
576             RETVAL
577              
578             U32
579             set_type(sv,arg)
580             SV *sv
581             U8 arg
582             INIT:
583 2           SAT *sat = _tipc_sanity_check(sv);
584             CODE:
585 2           switch(sat->addrtype) {
586             case TIPC_ADDR_NAME:
587 1           RETVAL = sat->addr.name.name.type = arg;
588 1           break;
589             case TIPC_ADDR_NAMESEQ:
590 1           RETVAL = sat->addr.nameseq.type = arg;
591 1           break;
592             default:
593 0           croak("set_type() called for a typeless sockaddr.");
594             }
595             OUTPUT:
596             RETVAL
597              
598             # And the address-conversion macros... (note: the .pm file wraps around the
599             # ones which have a _tipc_ prefix, so it can also accept "<1.2.3>" strings.)
600              
601             U32
602             _tipc_addr(zone,cluster,node)
603             U32 zone
604             U32 cluster
605             U32 node
606             CODE:
607 9           RETVAL = tipc_addr(zone, cluster, node);
608             OUTPUT:
609             RETVAL
610              
611             U32
612             _tipc_zone(addr)
613             U32 addr
614             CODE:
615 3           RETVAL = tipc_zone(addr);
616             OUTPUT:
617             RETVAL
618              
619             U32
620             _tipc_cluster(addr)
621             U32 addr
622             CODE:
623 3           RETVAL = tipc_cluster(addr);
624             OUTPUT:
625             RETVAL
626              
627             U32
628             _tipc_node(addr)
629             U32 addr
630             CODE:
631 3           RETVAL = tipc_node(addr);
632             OUTPUT:
633             RETVAL
634              
635              
636             # Finally, an SV which purposefully leaks scalars, to make sure the memory leak
637             # tester is effective. Returns true if it leaked a scalar, false otherwise.
638             # Don't ever call this.
639              
640             U32
641             __leak_a_scalar(sv)
642             SV *sv
643             CODE:
644 0           RETVAL = newSVpvf("leaky leak") ? 1 : 0;
645             OUTPUT:
646             RETVAL