1 /*
2 **
3 ** Copyright (C) 2011-2014 by Carnegie Mellon University
4 **
5 ** Use of the Net-Silk library and related source code is subject to the
6 ** terms of the following licenses:
7 **
8 ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
9 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
10 **
11 ** NO WARRANTY
12 **
13 ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
14 ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
15 ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
16 ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
17 ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
18 ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
19 ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
20 ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
21 ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
22 ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
23 ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
24 ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
25 ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
26 ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
27 ** DELIVERABLES UNDER THIS LICENSE.
28 **
29 ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
30 ** Mellon University, its trustees, officers, employees, and agents from
31 ** all claims or demands made against them (and any related losses,
32 ** expenses, or attorney's fees) arising out of, or relating to Licensee's
33 ** and/or its sub licensees' negligent use or willful misuse of or
34 ** negligent conduct or willful misconduct regarding the Software,
35 ** facilities, or other rights or assistance granted by Carnegie Mellon
36 ** University under this License, including, but not limited to, any
37 ** claims of product liability, personal injury, death, damage to
38 ** property, or violation of any laws or regulations.
39 **
40 ** Carnegie Mellon University Software Engineering Institute authored
41 ** documents are sponsored by the U.S. Department of Defense under
42 ** Contract FA8721-05-C-0003. Carnegie Mellon University retains
43 ** copyrights in all material produced under this contract. The U.S.
44 ** Government retains a non-exclusive, royalty-free license to publish or
45 ** reproduce these documents, or allow others to do so, for U.S.
46 ** Government purposes only pursuant to the copyright license under the
47 ** contract clause at 252.227.7013.
48 **
49 */
50 
51 #ifdef __cplusplus
52 extern "C" {
53 #endif
54 
55 #ifdef _CYGWIN
56 #include <windows.h>
57 #endif
58 
59 #ifdef _WIN32
60 #include <windows.h>
61 #endif
62 
63 #define PERL_NO_GET_CONTEXT
64 
65 #include "EXTERN.h"
66 #include "perl.h"
67 #include "XSUB.h"
68 
69 #define NEED_PL_signals 1
70 #include "ppport.h"
71 
72 #include "pthread.h"
73 
74 #define MATH_INT64_NATIVE_IF_AVAILABLE
75 #include "perl_math_int64.h"
76 
77 #include <nmsg.h>
78 #include <pcap.h>
79 
80 #ifdef _CYGWIN
81 #include <Win32-Extensions.h>
82 #endif
83 
84 typedef nmsg_message_t      Net__Nmsg__XS__msg;
85 typedef nmsg_io_t           Net__Nmsg__XS__io;
86 typedef nmsg_input_t        Net__Nmsg__XS__input;
87 typedef nmsg_input_t        Net__Nmsg__XS__input_file;
88 typedef nmsg_input_t        Net__Nmsg__XS__input_json;
89 typedef nmsg_input_t        Net__Nmsg__XS__input_sock;
90 typedef nmsg_input_t        Net__Nmsg__XS__input_pres;
91 typedef nmsg_input_t        Net__Nmsg__XS__input_pcap;
92 typedef nmsg_output_t       Net__Nmsg__XS__output;
93 typedef nmsg_output_t       Net__Nmsg__XS__output_file;
94 typedef nmsg_output_t       Net__Nmsg__XS__output_json;
95 typedef nmsg_output_t       Net__Nmsg__XS__output_sock;
96 typedef nmsg_output_t       Net__Nmsg__XS__output_pres;
97 typedef nmsg_output_t       Net__Nmsg__XS__output_cb;
98 typedef nmsg_rate_t         Net__Nmsg__XS__rate;
99 
100 typedef nmsg_pcap_t         Net__Nmsg__XS__nmsg_pcap;
101 typedef pcap_t             *Net__Nmsg__XS__pcap;
102 
103 typedef enum groknum_err_en {
104     GROKNUM_OK                =  0,  /* number ok                */
105     GROKNUM_ERR_NVREF         = -1,  /* invalid reference        */
106     GROKNUM_ERR_NAS           = -2,  /* not a string             */
107     GROKNUM_ERR_NAN           = -3,  /* not a number             */
108     GROKNUM_ERR_U16_OVERFLOW  = -4,  /* exceeds U16_MAX          */
109     GROKNUM_ERR_U32_OVERFLOW  = -5,  /* exceeds U32_MAX          */
110     GROKNUM_ERR_U64_OVERFLOW  = -6,  /* exceeds U64_MAX          */
111     GROKNUM_ERR_I16_OVERFLOW  = -7,  /* lt I16_MIN or gt I16_MAX */
112     GROKNUM_ERR_I32_OVERFLOW  = -8,  /* lt I32_MIN or gt I32_MAX */
113     GROKNUM_ERR_I64_OVERFLOW  = -9,  /* lt I64_MIN or gt I64_MAX */
114     GROKNUM_ERR_UNKNOWN       = -10, /* unknown                  */
115 } groknum_err_t;
116 
117 typedef union {
118     uint64_t    u64;
119     uint32_t    u32;
120     uint16_t    u16;
121     int64_t     i64;
122     int32_t     i32;
123     int16_t     i16;
124     int         en;
125     double      dbl;
126     bool        boo;
127 } nmsg_field_val_u;
128 
129 #include "strtoint64.h"
130 
131 #include <signal.h>
132 #include <assert.h>
133 
134 #ifdef __cplusplus
135 }
136 #endif
137 
138 #define NMSG_CLASS   "Net::Nmsg"
139 #define MSG_CLASS    "Net::Nmsg::Msg"
140 #define MSG_XS_CLASS "Net::Nmsg::XS::msg"
141 #define IPV4_CLASS   "Net::Nmsg::Field::IPv4"
142 #define IPV6_CLASS   "Net::Nmsg::Field::IPv6"
143 
144 #define MSG_SUBCLASS(class, vid, mid) \
145     sprintf(class, MSG_CLASS "::%s::%s", \
146                    nmsg_msgmod_vid_to_vname(vid), \
147                    nmsg_msgmod_msgtype_to_mname(vid, mid))
148 
149 #define NMSG_FF_REPEATED    0x01
150 #define NMSG_FF_REQUIRED    0x02
151 #define NMSG_FF_HIDDEN      0x04
152 #define NMSG_FF_NOPRINT     0x08
153 
154 #define GROKNUM_CROAK(rv, msg)                        \
155     switch (rv) {                                     \
156         case GROKNUM_ERR_NVREF:                       \
157             croak("%s: invalid reference", msg);      \
158         case GROKNUM_ERR_NAS:                         \
159             croak("%s: not a string", msg);           \
160         case GROKNUM_ERR_NAN:                         \
161             croak("%s: not an integer", msg);         \
162         case GROKNUM_ERR_U16_OVERFLOW:                \
163             croak("%s: uint16 overflow", msg);        \
164         case GROKNUM_ERR_U32_OVERFLOW:                \
165             croak("%s: uint32 overflow", msg);        \
166         case GROKNUM_ERR_U64_OVERFLOW:                \
167             croak("%s: uint64 overflow", msg);        \
168         case GROKNUM_ERR_I16_OVERFLOW:                \
169             croak("%s: int16 overflow", msg);         \
170         case GROKNUM_ERR_I32_OVERFLOW:                \
171             croak("%s: int32 overflow", msg);         \
172         case GROKNUM_ERR_I64_OVERFLOW:                \
173             croak("%s: int64 overflow", msg);         \
174         case GROKNUM_ERR_UNKNOWN:                     \
175             croak("%s: unknown error", msg);          \
176         default:                                      \
177             croak("%s: invalid error code (%d)", rv); \
178     }
179 
180 #define WRAP_MSG(m, msg) \
181     char class[100]; \
182     HV  *msg_stash; \
183     AV  *arr; \
184     MSG_SUBCLASS(class, nmsg_message_get_vid(m), nmsg_message_get_msgtype(m)); \
185     msg_stash = gv_stashpv(class, TRUE); \
186     arr = newAV(); \
187     av_push(arr, sv_setref_pv(newSV(0), MSG_XS_CLASS, (char *)m)); \
188     msg = sv_bless(newRV_noinc(MUTABLE_SV(arr)), msg_stash);
189 
190 /* callback hooks */
191 
192 static PerlInterpreter *orig_perl;
193 static pthread_mutex_t callback_lock = PTHREAD_MUTEX_INITIALIZER;
194 static pthread_mutex_t presentation_lock = PTHREAD_MUTEX_INITIALIZER;
195 
196 SV *
_xs_wrap_msg(pTHX_ nmsg_message_t m)197 _xs_wrap_msg(pTHX_ nmsg_message_t m) {
198     char class[100];
199     int32_t vid, mtype;
200     const char *vname, *mname;
201     HV  *msg_stash;
202     AV  *arr;
203 
204     vid = nmsg_message_get_vid(m);
205     vname = nmsg_msgmod_vid_to_vname(vid);
206     if (vname == NULL)
207         croak("unknown vendor id %d", vid);
208     mtype = nmsg_message_get_msgtype(m);
209     mname = nmsg_msgmod_msgtype_to_mname(vid, mtype);
210     if (mname == NULL)
211         croak("unknown vendor/message type %d/%d", vid, mtype);
212     sprintf(class, MSG_CLASS "::%s::%s", vname, mname);
213     msg_stash = gv_stashpv(class, TRUE);
214     arr = newAV();
215     av_push(arr, sv_setref_pv(newSV(0), MSG_XS_CLASS, (char *)m));
216     return(sv_bless(newRV_noinc(MUTABLE_SV(arr)), msg_stash));
217 }
218 
219 void
output_callback(nmsg_message_t m,void * callback)220 output_callback(nmsg_message_t m, void *callback) {
221 
222     //fprintf(stderr, "\n\nxs output_callback %p %p\n\n", m, callback);
223 
224     if (callback == NULL || m == NULL)
225         return;
226 
227     PERL_SET_CONTEXT(orig_perl);
228     pthread_mutex_lock(&callback_lock);
229 
230     { // C99 compliance
231 
232       dTHX;
233       dSP;
234 
235       ENTER;
236       SAVETMPS;
237       // push args onto stack
238       PUSHMARK(sp);
239       mXPUSHs(_xs_wrap_msg(aTHX_ m));
240       PUTBACK;
241       // re-wrap our callback CV in a reference and invoke perl function
242       call_sv(sv_2mortal(newRV(MUTABLE_SV(callback))), G_DISCARD);
243       // clean up
244       FREETMPS;
245       LEAVE;
246     }
247 
248     pthread_mutex_unlock(&callback_lock);
249 
250     //fprintf(stderr, "leaving callback fn\n");
251 }
252 
253 void
io_closed_callback(struct nmsg_io_close_event * ce)254 io_closed_callback(struct nmsg_io_close_event *ce) {
255 
256     if (ce->user == NULL ||
257         ce->io_type != nmsg_io_io_type_output ||
258         ce->close_type == nmsg_io_close_type_eof)
259         return;
260 
261     //fprintf(stderr, "io_closed_callback: 0x%x\n", (int)ce->user);
262 
263     PERL_SET_CONTEXT(orig_perl);
264     pthread_mutex_lock(&callback_lock);
265 
266     { // C99 compliance
267 
268       int   count;
269       IV    tmp;
270       SV   *ref;
271       void *ptr;
272 
273       dTHX;
274       dSP;
275 
276       ENTER;
277       SAVETMPS;
278       // push args onto stack
279       PUSHMARK(sp);
280       mXPUSHs(newSViv(ce->close_type));
281       //mXPUSHs(newSViv(ce->io_type));
282       PUTBACK;
283       // re-wrap callback CV in a reference and invoke perl function
284       count = call_sv(sv_2mortal(newRV(MUTABLE_SV(ce->user))), G_SCALAR);
285       SPAGAIN;
286       if (count != 1)
287           croak("single return value required from callback");
288       ref = POPs;
289       if (! SvROK(ref))
290           croak("not a reference");
291       tmp = SvIV(SvRV(ref));
292       ptr = INT2PTR(void *, tmp);
293       if (ptr != NULL) {
294           //fprintf(stderr, "xs reopen output %p\n", *(ce->output));
295           *(ce->output) = ptr;
296           //*(ce->output) = INT2PTR(nmsg_output_t, tmp);
297           //*(ce->output) = (nmsg_output_t)tmp;
298           //fprintf(stderr, "xs reopen output %p\n", *(ce->output));
299       }
300       PUTBACK;
301 
302       // clean up
303       FREETMPS;
304       LEAVE;
305     }
306 
307     pthread_mutex_unlock(&callback_lock);
308 
309     //fprintf(stderr, "io_closed_callback complete\n");
310 }
311 
312 groknum_err_t
_xs_pack_uint16_int(pTHX_ SV * sv,uint16_t * val)313 _xs_pack_uint16_int(pTHX_ SV *sv, uint16_t *val) {
314     UV uv;
315     IV iv;
316     NV nv;
317     int64_t  i64;
318     uint64_t u64;
319     groknum_err_t rv = GROKNUM_OK;
320 
321     if (SvIOK_UV(sv)) {
322         uv = SvUV(sv);
323         if (uv > UINT16_MAX)
324             rv = GROKNUM_ERR_U16_OVERFLOW;
325         *val = (uint16_t)uv;
326     }
327     else if (SvIOK(sv)) {
328         iv = SvIV(sv);
329         if (iv < 0 || iv > UINT16_MAX)
330             rv = GROKNUM_ERR_U16_OVERFLOW;
331         *val = (uint16_t)iv;
332     }
333     else if (SvNOK(sv)) {
334         nv = SvNV(sv);
335         if (nv < 0 || nv > UINT16_MAX)
336             rv = GROKNUM_ERR_U16_OVERFLOW;
337         *val = (uint16_t)SvUV(sv);
338     }
339     else if (SvU64OK(sv)) {
340         u64 = SvU64(sv);
341         if (u64 > UINT16_MAX)
342             rv = GROKNUM_ERR_U16_OVERFLOW;
343         *val = (uint16_t)u64;
344     }
345     else if (SvI64OK(sv)) {
346         i64 = SvI64(sv);
347         if (i64 < 0 || i64 > UINT16_MAX)
348             rv = GROKNUM_ERR_U16_OVERFLOW;
349         *val = (uint16_t)i64;
350     }
351     else
352         rv = GROKNUM_ERR_NAN;
353 
354     return rv;
355 }
356 
357 groknum_err_t
_xs_pack_uint16_strint(pTHX_ SV * sv,uint16_t * val)358 _xs_pack_uint16_strint(pTHX_ SV *sv, uint16_t *val) {
359     uint64_t       u64;
360     groknum_err_t  rv;
361 
362     if (!SvPOK(sv))
363         return GROKNUM_ERR_NAS;
364     rv = strtoint64(aTHX_ SvPV_nolen(sv), 0, 0, &u64);
365     switch (rv) {
366         case GROKNUM_OK:
367             if (u64 > UINT16_MAX)
368                 return GROKNUM_ERR_U16_OVERFLOW;
369             *val = (uint16_t)u64;
370             return GROKNUM_OK;
371         case GROKNUM_ERR_I64_OVERFLOW:
372         case GROKNUM_ERR_U64_OVERFLOW:
373             return GROKNUM_ERR_U16_OVERFLOW;
374         default:
375             return rv;
376     }
377     return GROKNUM_ERR_UNKNOWN;
378 }
379 
380 uint16_t
_xs_make_uint16(pTHX_ SV * sv)381 _xs_make_uint16(pTHX_ SV *sv) {
382     uint16_t      val;
383     groknum_err_t rv;
384 
385     rv = _xs_pack_uint16_int(aTHX_ sv, &val);
386     switch (rv) {
387         case GROKNUM_OK:
388             return val;
389         case GROKNUM_ERR_NAN:
390             break;
391         default:
392             GROKNUM_CROAK(rv, "invalid uint16");
393     }
394     // check for number-like strings
395     if (SvPOK(sv)) {
396         rv = _xs_pack_uint16_strint(aTHX_ sv, &val);
397         if (rv == GROKNUM_OK)
398             return val;
399         GROKNUM_CROAK(rv, "invalid uint16");
400     }
401     GROKNUM_CROAK(GROKNUM_ERR_NAN, "invalid uint16");
402 }
403 
404 groknum_err_t
_xs_pack_int16_int(pTHX_ SV * sv,int16_t * val)405 _xs_pack_int16_int(pTHX_ SV *sv, int16_t *val) {
406     UV uv;
407     IV iv;
408     NV nv;
409     int64_t  i64;
410     uint64_t u64;
411     groknum_err_t rv = GROKNUM_OK;
412 
413     if (SvIOK_UV(sv)) {
414         uv = SvUV(sv);
415         if (uv > UINT16_MAX)
416             rv = GROKNUM_ERR_I16_OVERFLOW;
417         *val = (int16_t)uv;
418     }
419     else if (SvIOK(sv)) {
420         iv = SvIV(sv);
421         if (iv < INT16_MIN || iv > INT16_MAX)
422             rv = GROKNUM_ERR_I16_OVERFLOW;
423         *val = (int16_t)iv;
424     }
425     else if (SvNOK(sv)) {
426         nv = SvNV(sv);
427         if (nv < INT16_MIN || nv > INT16_MAX)
428             rv = GROKNUM_ERR_I16_OVERFLOW;
429         *val = (int16_t)SvIV(sv);
430     }
431     else if (SvU64OK(sv)) {
432         u64 = SvU64(sv);
433         if (u64 > INT16_MAX)
434             rv = GROKNUM_ERR_I16_OVERFLOW;
435         *val = (int16_t)u64;
436     }
437     else if (SvI64OK(sv)) {
438         i64 = SvI64(sv);
439         if (i64 < INT16_MIN || i64 > INT16_MAX)
440             rv = GROKNUM_ERR_I16_OVERFLOW;
441         *val = (int16_t)i64;
442     }
443     else
444         rv = GROKNUM_ERR_NAN;
445 
446     return rv;
447 }
448 
449 groknum_err_t
_xs_pack_int16_strint(pTHX_ SV * sv,uint16_t * val)450 _xs_pack_int16_strint(pTHX_ SV *sv, uint16_t *val) {
451     uint64_t       i64;
452     groknum_err_t  rv;
453 
454     if (!SvPOK(sv))
455         return GROKNUM_ERR_NAS;
456     rv = strtoint64(aTHX_ SvPV_nolen(sv), 0, 1, &i64);
457     switch (rv) {
458         case GROKNUM_OK:
459             if (i64 < INT16_MIN || i64 > INT16_MAX)
460                 return GROKNUM_ERR_I16_OVERFLOW;
461             *val = (int16_t)i64;
462             return GROKNUM_OK;
463         case GROKNUM_ERR_I64_OVERFLOW:
464         case GROKNUM_ERR_U64_OVERFLOW:
465             return GROKNUM_ERR_I16_OVERFLOW;
466         default:
467             return rv;
468     }
469     return GROKNUM_ERR_UNKNOWN;
470 }
471 
472 int16_t
_xs_make_int16(pTHX_ SV * sv)473 _xs_make_int16(pTHX_ SV *sv) {
474     int16_t       val;
475     groknum_err_t rv;
476 
477     rv = _xs_pack_int16_int(aTHX_ sv, &val);
478     switch (rv) {
479         case GROKNUM_OK:
480             return val;
481         case GROKNUM_ERR_NAN:
482             break;
483         default:
484             GROKNUM_CROAK(rv, "invalid int16");
485     }
486     // check for number-like strings
487     if (SvPOK(sv)) {
488         rv = _xs_pack_int16_strint(aTHX_ sv, &val);
489         if (rv == GROKNUM_OK)
490             return val;
491         GROKNUM_CROAK(rv, "invalid int16");
492     }
493     GROKNUM_CROAK(GROKNUM_ERR_NAN, "invalid int16");
494 }
495 
496 groknum_err_t
_xs_pack_uint32_int(pTHX_ SV * sv,uint32_t * val)497 _xs_pack_uint32_int(pTHX_ SV *sv, uint32_t *val) {
498     UV uv;
499     IV iv;
500     NV nv;
501     int64_t  i64;
502     uint64_t u64;
503     groknum_err_t rv = GROKNUM_OK;
504 
505     if (SvIOK_UV(sv)) {
506         uv = SvUV(sv);
507         if (uv > UINT32_MAX)
508             rv = GROKNUM_ERR_U32_OVERFLOW;
509         *val = (uint32_t)uv;
510     }
511     else if (SvIOK(sv)) {
512         iv = SvIV(sv);
513         if (iv < 0 || iv > UINT32_MAX)
514             rv = GROKNUM_ERR_U32_OVERFLOW;
515         *val = (uint32_t)iv;
516     }
517     else if (SvNOK(sv)) {
518         nv = SvNV(sv);
519         if (nv < 0 || nv > UINT32_MAX)
520             rv = GROKNUM_ERR_U32_OVERFLOW;
521         *val = (uint32_t)SvUV(sv);
522     }
523     else if (SvU64OK(sv)) {
524         u64 = SvU64(sv);
525         if (u64 > UINT32_MAX)
526             rv = GROKNUM_ERR_U32_OVERFLOW;
527         *val = (uint32_t)u64;
528     }
529     else if (SvI64OK(sv)) {
530         i64 = SvI64(sv);
531         if (i64 < 0 || i64 > UINT32_MAX)
532             rv = GROKNUM_ERR_U32_OVERFLOW;
533         *val = (uint32_t)i64;
534     }
535     else
536         rv = GROKNUM_ERR_NAN;
537 
538     return rv;
539 }
540 
541 groknum_err_t
_xs_pack_uint32_strint(pTHX_ SV * sv,uint32_t * val)542 _xs_pack_uint32_strint(pTHX_ SV *sv, uint32_t *val) {
543     uint64_t       u64;
544     groknum_err_t  rv;
545 
546     if (!SvPOK(sv))
547         return GROKNUM_ERR_NAS;
548     rv = strtoint64(aTHX_ SvPV_nolen(sv), 0, 0, &u64);
549     switch (rv) {
550         case GROKNUM_OK:
551             if (u64 > UINT32_MAX)
552                 return GROKNUM_ERR_U32_OVERFLOW;
553             *val = (uint32_t)u64;
554             return GROKNUM_OK;
555         case GROKNUM_ERR_I64_OVERFLOW:
556         case GROKNUM_ERR_U64_OVERFLOW:
557             return GROKNUM_ERR_U32_OVERFLOW;
558         default:
559             return rv;
560     }
561     return GROKNUM_ERR_UNKNOWN;
562 }
563 
564 uint32_t
_xs_make_uint32(pTHX_ SV * sv)565 _xs_make_uint32(pTHX_ SV *sv) {
566     uint32_t      val;
567     groknum_err_t rv;
568 
569     rv = _xs_pack_uint32_int(aTHX_ sv, &val);
570     switch (rv) {
571         case GROKNUM_OK:
572             return val;
573         case GROKNUM_ERR_NAN:
574             break;
575         default:
576             GROKNUM_CROAK(rv, "invalid uint32");
577     }
578     // check for number-like strings
579     if (SvPOK(sv)) {
580         rv = _xs_pack_uint32_strint(aTHX_ sv, &val);
581         if (rv == GROKNUM_OK)
582             return val;
583         GROKNUM_CROAK(rv, "invalid uint32");
584     }
585     GROKNUM_CROAK(GROKNUM_ERR_NAN, "invalid uint32");
586 }
587 
588 groknum_err_t
_xs_pack_int32_int(pTHX_ SV * sv,int32_t * val)589 _xs_pack_int32_int(pTHX_ SV *sv, int32_t *val) {
590     UV uv;
591     IV iv;
592     NV nv;
593     int64_t  i64;
594     uint64_t u64;
595     groknum_err_t rv = GROKNUM_OK;
596 
597     if (SvIOK_UV(sv)) {
598         uv = SvUV(sv);
599         if (uv > INT32_MAX)
600             rv = GROKNUM_ERR_I32_OVERFLOW;
601         *val = (int32_t)uv;
602     }
603     else if (SvIOK(sv)) {
604         iv = SvIV(sv);
605         if (iv < INT32_MIN || iv > INT32_MAX)
606             rv = GROKNUM_ERR_I32_OVERFLOW;
607         *val = (int32_t)iv;
608     }
609     else if (SvNOK(sv)) {
610         nv = SvNV(sv);
611         if (nv < INT32_MIN || nv > INT32_MAX)
612             rv = GROKNUM_ERR_I32_OVERFLOW;
613         *val = (int32_t)SvIV(sv);
614     }
615     else if (SvU64OK(sv)) {
616         u64 = SvU64(sv);
617         if (u64 > INT32_MAX)
618             rv = GROKNUM_ERR_I32_OVERFLOW;
619         *val = (uint32_t)u64;
620     }
621     else if (SvI64OK(sv)) {
622         i64 = SvI64(sv);
623         if (i64 < INT32_MIN || i64 > INT32_MAX)
624             rv = GROKNUM_ERR_I32_OVERFLOW;
625         *val = (int32_t)i64;
626     }
627     else
628         rv = GROKNUM_ERR_NAN;
629 
630     return rv;
631 }
632 
633 groknum_err_t
_xs_pack_int32_strint(pTHX_ SV * sv,int32_t * val)634 _xs_pack_int32_strint(pTHX_ SV *sv, int32_t *val) {
635     int64_t        i64;
636     groknum_err_t  rv;
637 
638     if (!SvPOK(sv))
639         return GROKNUM_ERR_NAS;
640     rv = strtoint64(aTHX_ SvPV_nolen(sv), 0, 1, &i64);
641     switch (rv) {
642         case GROKNUM_OK:
643             if (i64 < INT32_MIN || i64 > INT32_MAX)
644                 return GROKNUM_ERR_I32_OVERFLOW;
645             *val = (int32_t)i64;
646             return GROKNUM_OK;
647         case GROKNUM_ERR_I64_OVERFLOW:
648         case GROKNUM_ERR_U64_OVERFLOW:
649             return GROKNUM_ERR_I32_OVERFLOW;
650         default:
651             return rv;
652     }
653     return GROKNUM_ERR_UNKNOWN;
654 }
655 
656 int32_t
_xs_make_int32(pTHX_ SV * sv)657 _xs_make_int32(pTHX_ SV *sv) {
658     int32_t       val;
659     groknum_err_t rv;
660 
661     rv = _xs_pack_int32_int(aTHX_ sv, &val);
662     switch (rv) {
663         case GROKNUM_OK:
664             return val;
665         case GROKNUM_ERR_NAN:
666             break;
667         default:
668             GROKNUM_CROAK(rv, "invalid int32");
669     }
670     // check for number-like strings
671     if (SvPOK(sv)) {
672         rv = _xs_pack_int32_strint(aTHX_ sv, &val);
673         if (rv == GROKNUM_OK)
674             return val;
675         GROKNUM_CROAK(rv, "invalid int32");
676     }
677     GROKNUM_CROAK(GROKNUM_ERR_NAN, "invalid int32");
678 }
679 
680 groknum_err_t
_xs_pack_uint64_int(pTHX_ SV * sv,uint64_t * val)681 _xs_pack_uint64_int(pTHX_ SV *sv, uint64_t *val) {
682     IV iv;
683     NV nv;
684     int64_t i64;
685 
686     if (SvIOK_UV(sv)) {
687         *val = (uint64_t)SvUV(sv);
688     }
689     else if (SvIOK(sv)) {
690         iv = SvIV(sv);
691         if (iv < 0)
692             return GROKNUM_ERR_U64_OVERFLOW;
693         *val = (uint64_t)iv;
694     }
695     else if (SvNOK(sv)) {
696         nv = SvNV(sv);
697         if (nv < 0 || nv > UINT64_MAX)
698             return GROKNUM_ERR_U64_OVERFLOW;
699         *val = (uint64_t)SvUV(sv);
700     }
701     else if (SvU64OK(sv)) {
702         *val = SvU64(sv);
703     }
704     else if (SvI64OK(sv)) {
705         i64 = SvI64(sv);
706         if (i64 < 0)
707             return GROKNUM_ERR_U64_OVERFLOW;
708         *val = (uint64_t)i64;
709     }
710     else
711         return GROKNUM_ERR_NAN;
712     return GROKNUM_OK;
713 }
714 
715 groknum_err_t
_xs_pack_uint64_strint(pTHX_ SV * sv,uint64_t * val)716 _xs_pack_uint64_strint(pTHX_ SV *sv, uint64_t *val) {
717     if (!SvPOK(sv))
718         return GROKNUM_ERR_NAS;
719     return strtoint64(aTHX_ SvPV_nolen(sv), 0, 0, val);
720 }
721 
722 uint64_t
_xs_make_uint64(pTHX_ SV * sv)723 _xs_make_uint64(pTHX_ SV *sv) {
724     uint64_t      val;
725     groknum_err_t rv;
726 
727     rv = _xs_pack_uint64_int(aTHX_ sv, &val);
728     switch (rv) {
729         case GROKNUM_OK:
730             return val;
731         case GROKNUM_ERR_NAN:
732             break;
733         default:
734             GROKNUM_CROAK(rv, "invalid uint64");
735     }
736     // check for number-like strings
737     if (SvPOK(sv)) {
738         rv = _xs_pack_uint64_strint(aTHX_ sv, &val);
739         if (rv == GROKNUM_OK)
740             return val;
741         GROKNUM_CROAK(rv, "invalid uint64");
742     }
743     GROKNUM_CROAK(GROKNUM_ERR_NAN, "invalid uint64");
744 }
745 
746 groknum_err_t
_xs_pack_int64_int(pTHX_ SV * sv,int64_t * i64)747 _xs_pack_int64_int(pTHX_ SV *sv, int64_t *i64) {
748     IV iv;
749     NV nv;
750     uint64_t u64;
751 
752     if (SvIOK_UV(sv)) {
753         *i64 = (int64_t)SvUV(sv);
754     }
755     else if (SvIOK(sv)) {
756         iv = SvIV(sv);
757         *i64 = (int64_t)iv;
758     }
759     else if (SvNOK(sv)) {
760         nv = SvNV(sv);
761         if (nv < INT64_MIN || nv > INT64_MAX)
762             return GROKNUM_ERR_I64_OVERFLOW;
763         *i64 = (int64_t)SvUV(sv);
764     }
765     else if (SvU64OK(sv)) {
766         u64 = SvU64(sv);
767         if (u64 > INT64_MAX)
768             return GROKNUM_ERR_I64_OVERFLOW;
769         *i64 = (int64_t)u64;
770     }
771     else if (SvI64OK(sv)) {
772         *i64 = SvI64(sv);
773     }
774     else
775         return GROKNUM_ERR_NAN;
776     return GROKNUM_OK;
777 }
778 
779 groknum_err_t
_xs_pack_int64_strint(pTHX_ SV * sv,int64_t * i64)780 _xs_pack_int64_strint(pTHX_ SV *sv, int64_t *i64) {
781     if (!SvPOK(sv))
782         return GROKNUM_ERR_NAS;
783     return strtoint64(aTHX_ SvPV_nolen(sv), 0, 1, i64);
784 }
785 
786 int64_t
_xs_make_int64(pTHX_ SV * sv)787 _xs_make_int64(pTHX_ SV *sv) {
788     int64_t       val;
789     groknum_err_t rv;
790 
791     rv = _xs_pack_int64_int(aTHX_ sv, &val);
792     switch (rv) {
793         case GROKNUM_OK:
794             return val;
795         case GROKNUM_ERR_NAN:
796             break;
797         default:
798             GROKNUM_CROAK(rv, "invalid int64");
799     }
800     // check for number-like strings
801     if (SvPOK(sv)) {
802         rv = _xs_pack_int64_strint(aTHX_ sv, &val);
803         if (rv == GROKNUM_OK)
804             return val;
805         GROKNUM_CROAK(rv, "invalid int64");
806     }
807     GROKNUM_CROAK(GROKNUM_ERR_NAN, "invalid int64");
808 }
809 
810 SV *
_xs_field_to_sv(pTHX_ void * data,size_t len,nmsg_msgmod_field_type type)811 _xs_field_to_sv(pTHX_ void *data, size_t len, nmsg_msgmod_field_type type) {
812 
813     if (data == NULL)
814         croak("oops null data pointer");
815 
816     switch (type) {
817 
818     case nmsg_msgmod_ft_enum:
819     case nmsg_msgmod_ft_int16:
820     case nmsg_msgmod_ft_int32:
821         return newSViv(*(int *)data);
822     case nmsg_msgmod_ft_uint16:
823     case nmsg_msgmod_ft_uint32:
824         return newSVuv(*(unsigned *)data);
825     case nmsg_msgmod_ft_double:
826         return newSVnv(*(double *)data);
827     case nmsg_msgmod_ft_bool:
828         return boolSV(newSViv(*(int *)data));
829     case nmsg_msgmod_ft_int64:
830         return newSVi64(*(int64_t *)data);
831     case nmsg_msgmod_ft_uint64:
832         return newSVu64(*(uint64_t *)data);
833     case nmsg_msgmod_ft_string:
834     case nmsg_msgmod_ft_mlstring:
835         // len includes trailing null
836         return newSVpv((char *)data, len - 1);
837     // case nmsg_msgmod_ft_ip:
838     // case nmsg_msgmod_ft_bytes:
839     default:
840         return newSVpvn((char *)data, len);
841     }
842 }
843 
844 uint8_t *
_xs_sv_to_field(pTHX_ SV * sv,nmsg_msgmod_field_type type,nmsg_field_val_u * data,size_t * len)845 _xs_sv_to_field(pTHX_ SV *sv, nmsg_msgmod_field_type type,
846                 nmsg_field_val_u *data, size_t *len) {
847     switch (type) {
848         case nmsg_msgmod_ft_int16:
849             data->i16 = _xs_make_int16(aTHX_ sv);
850             *len = sizeof(int16_t);
851             break;
852         case nmsg_msgmod_ft_uint16:
853             data->u16 = _xs_make_uint16(aTHX_ sv);
854             *len = sizeof(uint16_t);
855             break;
856         case nmsg_msgmod_ft_int32:
857             data->i32 = _xs_make_int32(aTHX_ sv);
858             *len = sizeof(int32_t);
859             break;
860         case nmsg_msgmod_ft_uint32:
861             data->u32 = _xs_make_uint32(aTHX_ sv);
862             *len = sizeof(uint32_t);
863             break;
864         case nmsg_msgmod_ft_int64:
865             data->i64 = _xs_make_int64(aTHX_ sv);
866             *len = sizeof(int64_t);
867             break;
868         case nmsg_msgmod_ft_uint64:
869             data->u64 = _xs_make_uint64(aTHX_ sv);
870             *len = sizeof(uint64_t);
871             break;
872         case nmsg_msgmod_ft_enum:
873             data->en = (int)SvIV(sv);
874             *len = sizeof(int);
875             break;
876         case nmsg_msgmod_ft_double:
877             data->dbl = (double)SvNV(sv);
878             break;
879         case nmsg_msgmod_ft_bool:
880             data->boo = (bool)SvTRUE(sv);
881             break;
882         case nmsg_msgmod_ft_string:
883         case nmsg_msgmod_ft_mlstring:
884             data = (void *)SvPV(sv, *len);
885             *len += 1;
886             break;
887         //case nmsg_msgmod_ft_ip:
888         //case nmsg_msgmod_ft_bytes:
889         default:
890             data = (void *)SvPV(sv, *len);
891             break;
892     }
893     return((uint8_t *)data);
894 }
895 
896 
897 MODULE = Net::Nmsg		PACKAGE = Net::Nmsg::Util
898 
899 BOOT:
900 #define MC(cc) \
901     newCONSTSUB(stash, #cc, newSViv( cc ))
902 //
903 #define MCE(name, ce) \
904     newCONSTSUB(stash, #name, newSViv( ce ))
905 //
906 #define MCPV(name, cc) \
907     newCONSTSUB(stash, #name, newSVpv( cc, sizeof(cc) ))
908 // BOOT ends after first blank line outside of a block
909 {
910     HV *stash;
911 
912     stash = gv_stashpv("Net::Nmsg::Util", TRUE);
913 
914     MC(NMSG_DEFAULT_SNAPLEN);
915     MC(NMSG_FLAG_FRAGMENT);
916     MC(NMSG_FLAG_ZLIB);
917     MC(NMSG_HDRLSZ_V2);
918     MC(NMSG_HDRSZ);
919     MC(NMSG_IPSZ_MAX);
920     MC(NMSG_LENHDRSZ_V1);
921     MC(NMSG_LENHDRSZ_V2);
922     MC(NMSG_PAYHDRSZ);
923     MC(NMSG_RBUFSZ);
924     MC(NMSG_RBUF_TIMEOUT);
925     MC(NMSG_VERSION);
926     MC(NMSG_WBUFSZ_ETHER);
927     MC(NMSG_WBUFSZ_JUMBO);
928     MC(NMSG_WBUFSZ_MAX);
929     MC(NMSG_WBUFSZ_MIN);
930 
931     MCE(NMSG_INPUT_TYPE,  nmsg_io_io_type_input );
932     MCE(NMSG_OUTPUT_TYPE, nmsg_io_io_type_output);
933 
934     MCE(NMSG_INPUT_TYPE_STREAM, nmsg_input_type_stream);
935     MCE(NMSG_INPUT_TYPE_PRES,   nmsg_input_type_pres  );
936     MCE(NMSG_INPUT_TYPE_PCAP,   nmsg_input_type_pcap  );
937 
938     MCE(NMSG_OUTPUT_TYPE_STREAM,   nmsg_output_type_stream  );
939     MCE(NMSG_OUTPUT_TYPE_PRES,     nmsg_output_type_pres    );
940     MCE(NMSG_OUTPUT_TYPE_CALLBACK, nmsg_output_type_callback);
941 
942     MCE(NMSG_OUTPUT_MODE_STRIPE, nmsg_io_output_mode_stripe);
943     MCE(NMSG_OUTPUT_MODE_MIRROR, nmsg_io_output_mode_mirror);
944 
945     MCE(NMSG_CLOSE_TYPE_EOF,      nmsg_io_close_type_eof     );
946     MCE(NMSG_CLOSE_TYPE_COUNT,    nmsg_io_close_type_count   );
947     MCE(NMSG_CLOSE_TYPE_INTERVAL, nmsg_io_close_type_interval);
948 
949     MCE(NMSG_PCAP_TYPE_FILE, nmsg_pcap_type_file);
950     MCE(NMSG_PCAP_TYPE_LIVE, nmsg_pcap_type_live);
951 
952     MCE(NMSG_RES_SUCCESS,          nmsg_res_success         );
953     MCE(NMSG_RES_FAILURE,          nmsg_res_failure         );
954     MCE(NMSG_RES_EOF,              nmsg_res_eof             );
955     MCE(NMSG_RES_MEMFAIL,          nmsg_res_memfail         );
956     MCE(NMSG_RES_PBUF_READY,       nmsg_res_pbuf_ready      );
957     MCE(NMSG_RES_NOTIMPL,          nmsg_res_notimpl         );
958     MCE(NMSG_RES_STOP,             nmsg_res_stop            );
959     MCE(NMSG_RES_AGAIN,            nmsg_res_again           );
960     MCE(NMSG_RES_PARSE_ERROR,      nmsg_res_parse_error     );
961     MCE(NMSG_RES_PCAP_ERROR,       nmsg_res_pcap_error      );
962     MCE(NMSG_RES_MAGIC_MISMATCH,   nmsg_res_magic_mismatch  );
963     MCE(NMSG_RES_VERSION_MISMATCH, nmsg_res_version_mismatch);
964 
965     MC(NMSG_FF_REPEATED);
966     MC(NMSG_FF_REQUIRED);
967     MC(NMSG_FF_HIDDEN);
968     MC(NMSG_FF_NOPRINT);
969 
970     MCE(NMSG_FT_ENUM,       nmsg_msgmod_ft_enum    );
971     MCE(NMSG_FT_BYTES,      nmsg_msgmod_ft_bytes   );
972     MCE(NMSG_FT_STRING,     nmsg_msgmod_ft_string  );
973     MCE(NMSG_FT_MLSTRING,   nmsg_msgmod_ft_mlstring);
974     MCE(NMSG_FT_IP,         nmsg_msgmod_ft_ip      );
975     MCE(NMSG_FT_UINT16,     nmsg_msgmod_ft_uint16  );
976     MCE(NMSG_FT_UINT32,     nmsg_msgmod_ft_uint32  );
977     MCE(NMSG_FT_UINT64,     nmsg_msgmod_ft_uint64  );
978     MCE(NMSG_FT_INT16,      nmsg_msgmod_ft_int16   );
979     MCE(NMSG_FT_INT32,      nmsg_msgmod_ft_int32   );
980     MCE(NMSG_FT_INT64,      nmsg_msgmod_ft_int64   );
981     MCE(NMSG_FT_DOUBLE,     nmsg_msgmod_ft_double  );
982     MCE(NMSG_FT_BOOL,       nmsg_msgmod_ft_bool    );
983 
984     MCE(NMSG_ALIAS_OPERATOR,    nmsg_alias_operator);
985     MCE(NMSG_ALIAS_GROUP,       nmsg_alias_group   );
986 
987     MATH_INT64_BOOT;
988 }
989 
990 
991 MODULE = Net::Nmsg		PACKAGE = Net::Nmsg     PREFIX = nmsg_
992 
993 void
994 _nmsg_init_lib()
995     PREINIT:
996     nmsg_res    res;
997     CODE:
998     if (NULL == orig_perl)
999         orig_perl = Perl_get_context();
1000     res = nmsg_init();
1001     if (res != nmsg_res_success)
1002         croak("nmsg_init failed: %s", nmsg_res_lookup(res));
1003 
1004 void
1005 nmsg_set_autoclose(autoclose)
1006     _Bool   autoclose
1007 
1008 void
1009 nmsg_set_debug(debug)
1010     int debug
1011 
1012 
1013 MODULE = Net::Nmsg		PACKAGE = Net::Nmsg::Util   PREFIX = nmsg_
1014 
1015 void
1016 nmsg_chalias_lookup(ch)
1017     const char *ch
1018     PREINIT:
1019     char **alias = NULL;
1020     int num_aliases;
1021     int i;
1022     PPCODE:
1023     num_aliases = nmsg_chalias_lookup(ch, &alias);
1024     if (num_aliases > 0) {
1025         for (i = 0; i < num_aliases; i++)
1026             mXPUSHs(newSVpv(alias[i], 0));
1027     }
1028     if (alias != NULL)
1029         nmsg_chalias_free(&alias);
1030 
1031 const char *
1032 nmsg_alias_by_key(ae, key)
1033 	nmsg_alias_e    ae
1034 	unsigned        key
1035 
1036 unsigned
1037 nmsg_alias_by_value(ae, value)
1038 	nmsg_alias_e    ae
1039 	const char     *value
1040 
1041 void
1042 find_all_devs()
1043     PREINIT:
1044     char    err[PCAP_ERRBUF_SIZE];
1045     PPCODE:
1046     pcap_if_t *devs, *d;
1047 
1048     if (pcap_findalldevs(&devs, err) == -1)
1049         croak("%s", err);
1050 
1051     for (d=devs; d; d=d->next) {
1052         mXPUSHs(newSVpv(d->name, 0));
1053         if (d->description)
1054             mXPUSHs(newSVpv(d->description, 0));
1055         else {
1056             if ((strcmp(d->name,"lo")  == 0) || (strcmp(d->name,"lo0") == 0))
1057                 mXPUSHs(newSVpv("loopback device", 0));
1058             else
1059                 mXPUSHs(newSVpv("unknown device", 0));
1060         }
1061     }
1062     pcap_freealldevs(devs);
1063 
1064 const char *
1065 lookup_result(val)
1066     enum nmsg_res val
1067     CODE:
1068     RETVAL = nmsg_res_lookup(val);
1069     OUTPUT:
1070     RETVAL
1071 
1072 void
1073 get_timestring()
1074     PREINIT:
1075     char    now[32];
1076     struct  timespec ts;
1077     struct  tm *tm;
1078     time_t  t;
1079     char   *tstr;
1080     PPCODE:
1081     nmsg_timespec_get(&ts);
1082     t = (time_t) ts.tv_sec;
1083     tm = gmtime(&t);
1084     strftime(now, sizeof(now), "%Y%m%d.%H%M.%s", tm);
1085     nmsg_asprintf(&tstr, "%s.%09ld", now, ts.tv_nsec);
1086     if (tstr == NULL)
1087         croak("problem allocating time string");
1088     mXPUSHs(newSVpv(tstr, 0));
1089     Safefree(tstr);
1090 
1091 
1092 MODULE = Net::Nmsg  PACKAGE = Net::Nmsg::Util   PREFIX = nmsg_msgmod_
1093 
1094 PROTOTYPES: ENABLE
1095 
1096 nmsg_msgmod_t
1097 _msgmod_lookup(vid, msgtype)
1098     unsigned    vid
1099     unsigned    msgtype
1100     CODE:
1101     RETVAL = nmsg_msgmod_lookup(vid, msgtype);
1102     OUTPUT:
1103     RETVAL
1104 
1105 size_t
1106 nmsg_msgmod_get_max_vid()
1107 
1108 size_t
1109 nmsg_msgmod_get_max_msgtype(vid)
1110 	unsigned    vid
1111 
1112 unsigned
1113 nmsg_msgmod_mname_to_msgtype(vid, mname)
1114 	unsigned    vid
1115 	const char *mname
1116 
1117 const char *
1118 nmsg_msgmod_msgtype_to_mname(vid, msgtype)
1119 	unsigned    vid
1120 	unsigned    msgtype
1121 
1122 const char *
1123 nmsg_msgmod_vid_to_vname(vid)
1124 	unsigned    vid
1125 
1126 unsigned
1127 nmsg_msgmod_vname_to_vid(vname)
1128 	char *vname
1129 
1130 
1131 MODULE = Net::Nmsg  PACKAGE = Net::Nmsg::XS::io PREFIX = nmsg_io_
1132 
1133 PROTOTYPES: ENABLE
1134 
1135 Net::Nmsg::XS::io
1136 init(CLASS)
1137   const char *CLASS
1138     CODE:
1139     PERL_UNUSED_VAR(CLASS);
1140     RETVAL = nmsg_io_init();
1141     OUTPUT:
1142     RETVAL
1143 
1144 void
1145 DESTROY(THIS)
1146 	Net::Nmsg::XS::io   THIS
1147     CODE:
1148     nmsg_io_destroy(&THIS);
1149 
1150 void
1151 nmsg_io_breakloop(THIS)
1152 	Net::Nmsg::XS::io   THIS
1153 
1154 void
1155 loop(THIS)
1156 	Net::Nmsg::XS::io   THIS
1157     PREINIT:
1158     nmsg_res    res;
1159     U32         SAVE_signals;
1160     CODE:
1161     SAVE_signals = PL_signals;
1162     PL_signals |= PERL_SIGNALS_UNSAFE_FLAG;
1163     res = nmsg_io_loop(THIS);
1164     PL_signals = SAVE_signals;
1165     if (res != nmsg_res_success)
1166         croak("loop failure(%d): %s", res, nmsg_res_lookup(res));
1167 
1168 void
1169 _add_input(THIS, input, ...)
1170 	Net::Nmsg::XS::io       THIS
1171     Net::Nmsg::XS::input    input
1172     PREINIT:
1173 	void *user = NULL;
1174     nmsg_res    res;
1175     CODE:
1176     if (items > 2) {
1177         if SvROK(ST(2))
1178             user = SvRV(ST(2));
1179         else if SvOK(ST(2))
1180             croak("not a reference");
1181     }
1182     res = nmsg_io_add_input(THIS, input, user);
1183     if (res != nmsg_res_success)
1184         croak("nmsg_io_add_input failed: %s", nmsg_res_lookup(res));
1185     if (user != NULL)
1186         nmsg_io_set_close_fp(THIS, io_closed_callback);
1187 
1188 void
1189 _add_output(THIS, output, ...)
1190 	Net::Nmsg::XS::io       THIS
1191 	Net::Nmsg::XS::output   output
1192     PREINIT:
1193 	void *user = NULL;
1194     nmsg_res    res;
1195     CODE:
1196     if (items > 2) {
1197         if SvROK(ST(2))
1198             user = SvRV(ST(2));
1199         else if SvOK(ST(2))
1200             croak("not a reference");
1201     }
1202     res = nmsg_io_add_output(THIS, output, user);
1203     if (res != nmsg_res_success)
1204         croak("nmsg_io_add_output failed: %s", nmsg_res_lookup(res));
1205     if (user != NULL)
1206         nmsg_io_set_close_fp(THIS, io_closed_callback);
1207 
1208 void
1209 nmsg_io_set_count(THIS, value)
1210 	Net::Nmsg::XS::io   THIS
1211 	unsigned            value
1212 
1213 void
1214 nmsg_io_set_debug(THIS, value)
1215 	Net::Nmsg::XS::io   THIS
1216 	unsigned            value
1217 
1218 void
1219 nmsg_io_set_interval(THIS, value)
1220 	Net::Nmsg::XS::io   THIS
1221 	unsigned            value
1222 
1223 void
1224 nmsg_io_set_interval_randomized(THIS, value)
1225 	Net::Nmsg::XS::io   THIS
1226 	bool                value
1227 
1228 void
1229 nmsg_io_set_output_mode(THIS, value)
1230 	Net::Nmsg::XS::io   THIS
1231 	nmsg_io_output_mode value
1232 
1233 void
1234 set_mirror(THIS, value)
1235 	Net::Nmsg::XS::io   THIS
1236 	unsigned            value
1237     CODE:
1238     if (value > 0)
1239         nmsg_io_set_output_mode(THIS, nmsg_io_output_mode_mirror);
1240     else
1241         nmsg_io_set_output_mode(THIS, nmsg_io_output_mode_stripe);
1242 
1243 
1244 MODULE = Net::Nmsg  PACKAGE = Net::Nmsg::XS::nmsg_pcap  PREFIX=nmsg_pcap_
1245 
1246 PROTOTYPES: ENABLE
1247 
1248 Net::Nmsg::XS::nmsg_pcap
1249 _input_open(CLASS, pcap)
1250     const char          *CLASS
1251     Net::Nmsg::XS::pcap  pcap
1252     CODE:
1253     PERL_UNUSED_VAR(CLASS);
1254     RETVAL = nmsg_pcap_input_open(pcap);
1255     if (RETVAL == NULL)
1256         croak("nmsg_pcap_input_open() failed");
1257     OUTPUT:
1258     RETVAL
1259 
1260 void
1261 destroy(THIS)
1262     Net::Nmsg::XS::nmsg_pcap    THIS
1263     PREINIT:
1264     nmsg_res    res;
1265     CODE:
1266     res = nmsg_pcap_input_close(&THIS);
1267     if (res != nmsg_res_success)
1268         fprintf(stderr, "nmsg_pcap_input_close failed: %s", nmsg_res_lookup(res));
1269 
1270 void
1271 set_bpf(THIS, bpf)
1272     Net::Nmsg::XS::nmsg_pcap    THIS
1273     char *bpf
1274     PREINIT:
1275     nmsg_res    res;
1276     CODE:
1277     res = nmsg_pcap_input_setfilter(THIS, bpf);
1278     if (res != nmsg_res_success)
1279         croak("nmsg_pcap_input_setfilter failed: %s", nmsg_res_lookup(res));
1280 
1281 nmsg_pcap_type
1282 nmsg_pcap_get_type(THIS)
1283 	Net::Nmsg::XS::nmsg_pcap    THIS
1284 
1285 
1286 MODULE = Net::Nmsg  PACKAGE = Net::Nmsg::XS::pcap   PREFIX = pcap_
1287 
1288 PROTOTYPES: ENABLE
1289 
1290 Net::Nmsg::XS::pcap
1291 open_offline(CLASS, fname)
1292     const char  *CLASS
1293     const char  *fname
1294     PREINIT:
1295     char    err[PCAP_ERRBUF_SIZE];
1296     CODE:
1297     PERL_UNUSED_VAR(CLASS);
1298     RETVAL = pcap_open_offline(fname, err);
1299     if (RETVAL == NULL)
1300         croak("pcap_open_offline() failed: %s", err);
1301     OUTPUT:
1302     RETVAL
1303 
1304 Net::Nmsg::XS::pcap
1305 open_live(CLASS, iface, snaplen, promisc)
1306     const char *CLASS
1307     const char *iface
1308     int         snaplen
1309     int         promisc
1310     PREINIT:
1311     char    err[PCAP_ERRBUF_SIZE];
1312     CODE:
1313     PERL_UNUSED_VAR(CLASS);
1314     RETVAL = pcap_open_live(iface, snaplen, promisc, 0, err);
1315     if (RETVAL == NULL)
1316         croak("pcap_open_offline() failed: %s", err);
1317     OUTPUT:
1318     RETVAL
1319 
1320 void
1321 destroy(THIS)
1322     Net::Nmsg::XS::pcap THIS
1323     CODE:
1324     pcap_close(THIS);
1325 
1326 int
1327 set_snaplen(THIS, snaplen)
1328     Net::Nmsg::XS::pcap THIS
1329     int                 snaplen
1330     CODE:
1331 #ifdef LIMITED_PCAP
1332     PERL_UNUSED_VAR(snaplen);
1333     croak("pcap_set_snaplen unavailable in this version of libpcap");
1334 #else
1335     RETVAL = pcap_set_snaplen(THIS, snaplen);
1336 #endif /* LIMITED_PCAP */
1337     OUTPUT:
1338     RETVAL
1339 
1340 int
1341 set_promisc(THIS, promisc)
1342     Net::Nmsg::XS::pcap THIS
1343     int                 promisc
1344     CODE:
1345 #ifdef LIMITED_PCAP
1346     PERL_UNUSED_VAR(promisc);
1347     croak("pcap_set_promisc unavailable in this version of libpcap");
1348 #else
1349     RETVAL = pcap_set_promisc(THIS, promisc);
1350 #endif /* LIMITED_PCAP */
1351     OUTPUT:
1352     RETVAL
1353 
1354 void
1355 get_selectable_fd(THIS)
1356     Net::Nmsg::XS::pcap THIS
1357     PREINIT:
1358     int res;
1359     PPCODE:
1360     res = pcap_get_selectable_fd(THIS);
1361     if (res != -1)
1362         mXPUSHi(res);
1363 
1364 int
1365 pcap_fileno(THIS)
1366     Net::Nmsg::XS::pcap THIS
1367 
1368 char *
1369 pcap_geterr(THIS)
1370     Net::Nmsg::XS::pcap THIS
1371 
1372 
1373 MODULE = Net::Nmsg  PACKAGE = Net::Nmsg::XS::input  PREFIX = nmsg_input_
1374 
1375 PROTOTYPES: ENABLE
1376 
1377 void
1378 destroy(THIS)
1379     Net::Nmsg::XS::input    THIS
1380     CODE:
1381     nmsg_input_close(&THIS);
1382 
1383 Net::Nmsg::XS::input_file
1384 nmsg_input_open_file(CLASS, fh)
1385     const char   *CLASS
1386     PerlIO *fh
1387     CODE:
1388     PERL_UNUSED_VAR(CLASS);
1389     RETVAL = nmsg_input_open_file(PerlIO_fileno(fh));
1390     if (RETVAL == NULL)
1391         croak("nmsg_input_open_file() failed");
1392     OUTPUT:
1393     RETVAL
1394 
1395 Net::Nmsg::XS::input_json
1396 nmsg_input_open_json(CLASS, fh)
1397     const char   *CLASS
1398     PerlIO *fh
1399     CODE:
1400     PERL_UNUSED_VAR(CLASS);
1401     RETVAL = nmsg_input_open_json(PerlIO_fileno(fh));
1402     if (RETVAL == NULL)
1403         croak("nmsg_input_open_json() failed");
1404     OUTPUT:
1405     RETVAL
1406 
1407 Net::Nmsg::XS::input_sock
1408 nmsg_input_open_sock(CLASS, fh)
1409     const char   *CLASS
1410     PerlIO *fh
1411     CODE:
1412     PERL_UNUSED_VAR(CLASS);
1413     RETVAL = nmsg_input_open_sock(PerlIO_fileno(fh));
1414     if (RETVAL == NULL)
1415         croak("nmsg_input_open_sock() failed");
1416     OUTPUT:
1417     RETVAL
1418 
1419 Net::Nmsg::XS::input_pres
1420 _open_pres(CLASS, fh, vid, mid)
1421     const char  *CLASS
1422     PerlIO      *fh
1423     unsigned     vid
1424     unsigned     mid
1425     PREINIT:
1426     nmsg_msgmod_t   mod;
1427     CODE:
1428     PERL_UNUSED_VAR(CLASS);
1429     mod = nmsg_msgmod_lookup(vid, mid);
1430     if (mod == NULL)
1431         croak("unknown vendor id '%d' or message type '%d'", vid, mid);
1432     RETVAL = nmsg_input_open_pres(PerlIO_fileno(fh), mod);
1433     if (RETVAL == NULL)
1434         croak("nmsg_input_open_pres() failed");
1435     OUTPUT:
1436     RETVAL
1437 
1438 Net::Nmsg::XS::input_pcap
1439 _open_pcap(CLASS, pcap, vid, mid)
1440     const char                 *CLASS
1441     Net::Nmsg::XS::nmsg_pcap    pcap
1442     unsigned                    vid
1443     unsigned                    mid
1444     PREINIT:
1445     nmsg_msgmod_t   mod;
1446     CODE:
1447     PERL_UNUSED_VAR(CLASS);
1448     mod = nmsg_msgmod_lookup(vid, mid);
1449     if (mod == NULL)
1450         croak("unknown vendor id '%d' or message type '%d'", vid, mid);
1451     RETVAL = nmsg_input_open_pcap(pcap, mod);
1452     if (RETVAL == NULL)
1453         croak("nmsg_input_open_pcap() failed");
1454     OUTPUT:
1455     RETVAL
1456 
1457 void
1458 nmsg_input_set_filter_source(THIS, value)
1459 	Net::Nmsg::XS::input    THIS
1460 	unsigned    value
1461 
1462 void
1463 _set_filter_group(THIS, value)
1464 	Net::Nmsg::XS::input    THIS
1465 	unsigned    value
1466         CODE:
1467         nmsg_input_set_filter_group(THIS, value);
1468 
1469 void
1470 _set_filter_operator(THIS, value)
1471 	Net::Nmsg::XS::input    THIS
1472 	unsigned    value
1473         CODE:
1474         nmsg_input_set_filter_operator(THIS, value);
1475 
1476 void
1477 _set_filter_msgtype(THIS, vid, mid)
1478 	Net::Nmsg::XS::input    THIS
1479 	unsigned    vid
1480 	unsigned    mid
1481     CODE:
1482     nmsg_input_set_filter_msgtype(THIS, vid, mid);
1483 
1484 void
1485 nmsg_input_set_blocking_io(THIS, flag)
1486     Net::Nmsg::XS::input    THIS
1487     bool    flag
1488     PREINIT:
1489     nmsg_res    res;
1490     PPCODE:
1491     res = nmsg_input_set_blocking_io(THIS, flag);
1492     if (res == nmsg_res_success)
1493         mXPUSHi(flag);
1494 
1495 void
1496 read(THIS, blocking_io=true)
1497     Net::Nmsg::XS::input    THIS
1498     bool                    blocking_io
1499     PREINIT:
1500     nmsg_message_t  m;
1501     nmsg_res        res;
1502     U32             SAVE_signals;
1503     PPCODE:
1504     res = nmsg_res_failure;
1505     while (res != nmsg_res_success) {
1506         SAVE_signals = PL_signals;
1507         PL_signals |= PERL_SIGNALS_UNSAFE_FLAG;
1508         res = nmsg_input_read(THIS, &m);
1509         PL_signals = SAVE_signals;
1510         switch (res) {
1511         case (nmsg_res_success):
1512             mXPUSHs(_xs_wrap_msg(aTHX_ m));
1513             goto last_read;
1514         case (nmsg_res_again):
1515             if (blocking_io != true)
1516                 goto last_read;
1517             break;
1518         case (nmsg_res_eof):
1519             goto last_read;
1520         default:
1521             croak("nmsg_input_read() failed: %s", nmsg_res_lookup(res));
1522         }
1523     }
1524     last_read:
1525         // return
1526 
1527 nmsg_res
1528 loop(THIS, cb, count)
1529     Net::Nmsg::XS::input    THIS
1530     int     count
1531     CV     *cb
1532     PREINIT:
1533     nmsg_res    res;
1534     U32         SAVE_signals;
1535     CODE:
1536     SAVE_signals = PL_signals;
1537     PL_signals |= PERL_SIGNALS_UNSAFE_FLAG;
1538     res = nmsg_input_loop(THIS, count, output_callback, (void *)cb);
1539     PL_signals = SAVE_signals;
1540     if (res != nmsg_res_success && res != nmsg_res_eof)
1541         croak("nmsg_input_loop() failed(%d): %s", res, nmsg_res_lookup(res));
1542     RETVAL = res;
1543     OUTPUT:
1544     RETVAL
1545 
1546 
1547 MODULE = Net::Nmsg  PACKAGE = Net::Nmsg::XS::output PREFIX = nmsg_output_
1548 
1549 PROTOTYPES: ENABLE
1550 
1551 void
1552 destroy(THIS)
1553     Net::Nmsg::XS::output   THIS
1554     CODE:
1555     nmsg_output_close(&THIS);
1556 
1557 Net::Nmsg::XS::output_file
1558 open_file(CLASS, fh, bufsz)
1559     const char   *CLASS
1560     PerlIO *fh
1561     size_t  bufsz
1562     CODE:
1563     PERL_UNUSED_VAR(CLASS);
1564     RETVAL = nmsg_output_open_file(PerlIO_fileno(fh), bufsz);
1565     OUTPUT:
1566     RETVAL
1567 
1568 Net::Nmsg::XS::output_json
1569 open_json(CLASS, fh)
1570     const char   *CLASS
1571     PerlIO *fh
1572     CODE:
1573     PERL_UNUSED_VAR(CLASS);
1574     RETVAL = nmsg_output_open_json(PerlIO_fileno(fh));
1575     OUTPUT:
1576     RETVAL
1577 
1578 Net::Nmsg::XS::output_sock
1579 open_sock(CLASS, fh, bufsz)
1580     const char   *CLASS
1581     PerlIO *fh
1582     size_t  bufsz
1583     CODE:
1584     PERL_UNUSED_VAR(CLASS);
1585     RETVAL = nmsg_output_open_sock(PerlIO_fileno(fh), bufsz);
1586     OUTPUT:
1587     RETVAL
1588 
1589 Net::Nmsg::XS::output_pres
1590 open_pres(CLASS, fh)
1591     const char   *CLASS
1592     PerlIO *fh
1593     CODE:
1594     PERL_UNUSED_VAR(CLASS);
1595     RETVAL = nmsg_output_open_pres(PerlIO_fileno(fh));
1596     OUTPUT:
1597     RETVAL
1598 
1599 Net::Nmsg::XS::output_cb
1600 open_callback(CLASS, cb)
1601     const char    *CLASS
1602     CV      *cb
1603     CODE:
1604     PERL_UNUSED_VAR(CLASS);
1605     RETVAL = nmsg_output_open_callback(output_callback, (void *)cb);
1606     OUTPUT:
1607     RETVAL
1608 
1609 void
1610 nmsg_output_set_buffered(THIS, value)
1611 	Net::Nmsg::XS::output   THIS
1612 	bool    value
1613 
1614 void
1615 nmsg_output_set_endline(THIS, value)
1616 	Net::Nmsg::XS::output   THIS
1617 	const char *value
1618 
1619 void
1620 nmsg_output_set_rate(THIS, rate, freq, rate_obj)
1621     Net::Nmsg::XS::output THIS
1622     unsigned              rate
1623     unsigned              freq
1624     Net::Nmsg::XS::rate   rate_obj
1625     CODE:
1626     PERL_UNUSED_VAR(rate);
1627     PERL_UNUSED_VAR(freq);
1628     nmsg_output_set_rate(THIS, rate_obj);
1629 
1630 void
1631 nmsg_output_set_zlibout(THIS, value)
1632 	Net::Nmsg::XS::output   THIS
1633 	bool    value
1634 
1635 void
1636 nmsg_output_set_group(THIS, value)
1637 	Net::Nmsg::XS::output   THIS
1638 	unsigned    value
1639 
1640 void
1641 nmsg_output_set_operator(THIS, value)
1642 	Net::Nmsg::XS::output   THIS
1643 	unsigned    value
1644 
1645 void
1646 nmsg_output_set_source(THIS, value)
1647 	Net::Nmsg::XS::output   THIS
1648 	unsigned    value
1649 
1650 void
1651 nmsg_output_set_filter_msgtype(THIS, vid, mid)
1652 	Net::Nmsg::XS::output   THIS
1653 	unsigned    vid
1654 	unsigned    mid
1655 
1656 void
1657 _write(THIS, msg)
1658     Net::Nmsg::XS::output   THIS
1659     Net::Nmsg::XS::msg      msg
1660     PREINIT:
1661     nmsg_res    res;
1662     U32         SAVE_signals;
1663     CODE:
1664     SAVE_signals = PL_signals;
1665     PL_signals |= PERL_SIGNALS_UNSAFE_FLAG;
1666     res = nmsg_output_write(THIS, msg);
1667     PL_signals = SAVE_signals;
1668     if (res != nmsg_res_success)
1669         croak("nmsg_output_write() failed: %s", nmsg_res_lookup(res));
1670 
1671 
1672 MODULE = Net::Nmsg  PACKAGE = Net::Nmsg::XS::rate PREFIX = nmsg_rate_
1673 
1674 PROTOTYPES: ENABLE
1675 
1676 Net::Nmsg::XS::rate
1677 nmsg_rate_init(CLASS, rate, freq)
1678     char           *CLASS
1679     unsigned        rate
1680     unsigned        freq
1681     CODE:
1682     PERL_UNUSED_VAR(CLASS);
1683     RETVAL = nmsg_rate_init(rate, freq);
1684     if (RETVAL == NULL)
1685         croak("rate error %d/%d", rate, freq);
1686     OUTPUT:
1687     RETVAL
1688 
1689 void
1690 DESTROY(THIS)
1691     Net::Nmsg::XS::rate THIS
1692     CODE:
1693     nmsg_rate_destroy(&THIS);
1694 
1695 
1696 MODULE = Net::Nmsg  PACKAGE = Net::Nmsg::XS::msg PREFIX = nmsg_message_
1697 
1698 PROTOTYPES: ENABLE
1699 
1700 Net::Nmsg::XS::msg
1701 nmsg_message_init(CLASS, mod)
1702     char           *CLASS
1703     nmsg_msgmod_t   mod
1704     CODE:
1705     PERL_UNUSED_VAR(CLASS);
1706     RETVAL = nmsg_message_init(mod);
1707     OUTPUT:
1708     RETVAL
1709 
1710 void
1711 DESTROY(THIS)
1712     Net::Nmsg::XS::msg  THIS
1713     CODE:
1714     nmsg_message_destroy(&THIS);
1715 
1716 uint32_t
1717 nmsg_message_get_source(THIS)
1718     Net::Nmsg::XS::msg  THIS
1719 
1720 uint32_t
1721 nmsg_message_get_operator(THIS)
1722     Net::Nmsg::XS::msg  THIS
1723 
1724 uint32_t
1725 nmsg_message_get_group(THIS)
1726     Net::Nmsg::XS::msg  THIS
1727 
1728 void
1729 get_time(THIS)
1730     Net::Nmsg::XS::msg  THIS
1731     PREINIT:
1732     struct timespec ts;
1733     PPCODE:
1734     nmsg_message_get_time(THIS, &ts);
1735     mXPUSHi(ts.tv_sec);
1736     mXPUSHi(ts.tv_nsec);
1737 
1738 void
1739 get_num_fields(THIS)
1740     Net::Nmsg::XS::msg  THIS
1741     PREINIT:
1742     nmsg_res  res;
1743     size_t    len;
1744     PPCODE:
1745     res = nmsg_message_get_num_fields(THIS, &len);
1746     if (res == nmsg_res_success)
1747         mXPUSHu(len);
1748 
1749 void
1750 get_num_field_values(THIS, field)
1751     Net::Nmsg::XS::msg  THIS
1752     const char         *field
1753     PREINIT:
1754     nmsg_res  res;
1755     size_t    len;
1756     PPCODE:
1757     res = nmsg_message_get_num_field_values(THIS, field, &len);
1758     if (res == nmsg_res_success)
1759         mXPUSHu(len);
1760 
1761 void
1762 get_num_field_values_by_idx(THIS, idx)
1763     Net::Nmsg::XS::msg  THIS
1764     unsigned            idx
1765     PREINIT:
1766     nmsg_res  res;
1767     size_t    len;
1768     PPCODE:
1769     res = nmsg_message_get_num_field_values_by_idx(THIS, idx, &len);
1770     if (res == nmsg_res_success)
1771         mXPUSHu(len);
1772 
1773 void
1774 get_field(THIS, field, v_idx = 0)
1775     Net::Nmsg::XS::msg  THIS
1776     const char         *field
1777     unsigned            v_idx
1778     PREINIT:
1779     nmsg_res                res;
1780     size_t                  len;
1781     void                   *data;
1782     nmsg_msgmod_field_type  type;
1783     PPCODE:
1784     res = nmsg_message_get_field(THIS, field, v_idx, &data, &len);
1785     if (res == nmsg_res_success && data != NULL) {
1786         res = nmsg_message_get_field_type(THIS, field, &type);
1787         if (res == nmsg_res_success) {
1788             mXPUSHs(_xs_field_to_sv(aTHX_ data, len, type));
1789         }
1790         else
1791             croak("nmsg_message_get_field_type failed: %s",
1792                   nmsg_res_lookup(res));
1793     }
1794 
1795 void
1796 get_field_vals(THIS, field)
1797     Net::Nmsg::XS::msg  THIS
1798     const char         *field
1799     PREINIT:
1800     nmsg_res                res;
1801     size_t                  len;
1802     void                   *data;
1803     nmsg_msgmod_field_type  type;
1804     int                     i;
1805     PPCODE:
1806     res = nmsg_message_get_field_type(THIS, field, &type);
1807     if (res != nmsg_res_success)
1808         croak("nmsg_message_get_field_type failed: %s", nmsg_res_lookup(res));
1809     for (i = 0; ; i++) {
1810         res = nmsg_message_get_field(THIS, field, i, &data, &len);
1811         if (res != nmsg_res_success || data == NULL)
1812             break;
1813         mXPUSHs(_xs_field_to_sv(aTHX_ data, len, type));
1814     }
1815 
1816 void
1817 get_field_by_idx(THIS, f_idx, v_idx = 0)
1818     Net::Nmsg::XS::msg  THIS
1819     unsigned            f_idx
1820     unsigned            v_idx
1821     PREINIT:
1822     nmsg_res               res;
1823     nmsg_msgmod_field_type type;
1824     size_t                 len;
1825     void                  *data;
1826     PPCODE:
1827     res = nmsg_message_get_field_by_idx(THIS, f_idx, v_idx, &data, &len);
1828     if (res == nmsg_res_success) {
1829         res = nmsg_message_get_field_type_by_idx(THIS, f_idx, &type);
1830         if (res == nmsg_res_success && data != NULL) {
1831             mXPUSHs(_xs_field_to_sv(aTHX_ data, len, type));
1832         }
1833         else if (res != nmsg_res_success)
1834             croak("nmsg_message_get_field_type_by_idx failed: %s",
1835                   nmsg_res_lookup(res));
1836     }
1837 
1838 void
1839 get_field_vals_by_idx(THIS, f_idx)
1840     Net::Nmsg::XS::msg  THIS
1841     unsigned            f_idx
1842     PREINIT:
1843     nmsg_res                res;
1844     nmsg_msgmod_field_type  type;
1845     size_t                  len;
1846     void                   *data;
1847     int                     i;
1848     PPCODE:
1849     res = nmsg_message_get_field_type_by_idx(THIS, f_idx, &type);
1850     if (res == nmsg_res_success) {
1851         for (i = 0; ; i++) {
1852             res = nmsg_message_get_field_by_idx(THIS, f_idx, i, &data, &len);
1853             if (res != nmsg_res_success || data == NULL)
1854                 break;
1855             mXPUSHs(_xs_field_to_sv(aTHX_ data, len, type));
1856         }
1857     }
1858 
1859 void
1860 get_field_flags(THIS, field)
1861     Net::Nmsg::XS::msg  THIS
1862     const char         *field
1863     PREINIT:
1864     nmsg_res    res;
1865     unsigned    flags;
1866     PPCODE:
1867     res = nmsg_message_get_field_flags(THIS, field, &flags);
1868     if (res == nmsg_res_success)
1869         mXPUSHu(flags);
1870 
1871 void
1872 get_field_flags_by_idx(THIS, f_idx)
1873     Net::Nmsg::XS::msg  THIS
1874     unsigned            f_idx
1875     PREINIT:
1876     nmsg_res    res;
1877     unsigned    flags;
1878     PPCODE:
1879     res = nmsg_message_get_field_flags_by_idx(THIS, f_idx, &flags);
1880     if (res == nmsg_res_success)
1881         mXPUSHu(flags);
1882 
1883 void
1884 get_field_idx(THIS, name)
1885     Net::Nmsg::XS::msg  THIS
1886     const char         *name
1887     PREINIT:
1888     nmsg_res    res;
1889     unsigned    idx;
1890     PPCODE:
1891     res = nmsg_message_get_field_idx(THIS, name, &idx);
1892     if (res == nmsg_res_success)
1893         mXPUSHu(idx);
1894 
1895 void
1896 get_field_name(THIS, idx)
1897     Net::Nmsg::XS::msg  THIS
1898     unsigned            idx
1899     PREINIT:
1900     nmsg_res    res;
1901     const char *name;
1902     PPCODE:
1903     res = nmsg_message_get_field_name(THIS, idx, &name);
1904     if (res == nmsg_res_success)
1905         mXPUSHs(newSVpv(name, 0));
1906 
1907 void
1908 get_field_type(THIS, name)
1909     Net::Nmsg::XS::msg  THIS
1910     const char         *name;
1911     PREINIT:
1912     nmsg_res                res;
1913     nmsg_msgmod_field_type  type;
1914     PPCODE:
1915     res = nmsg_message_get_field_type(THIS, name, &type);
1916     if (res == nmsg_res_success)
1917         mXPUSHi(type);
1918 
1919 void
1920 get_field_type_by_idx(THIS, idx)
1921     Net::Nmsg::XS::msg  THIS
1922     unsigned            idx
1923     PREINIT:
1924     nmsg_res                res;
1925     nmsg_msgmod_field_type  type;
1926     PPCODE:
1927     res = nmsg_message_get_field_type_by_idx(THIS, idx, &type);
1928     if (res == nmsg_res_success)
1929         mXPUSHi(type);
1930 
1931 void
1932 enum_name_to_value(THIS, field, name)
1933     Net::Nmsg::XS::msg  THIS
1934     const char         *field
1935     const char         *name
1936     PREINIT:
1937     nmsg_res    res;
1938     unsigned    value;
1939     PPCODE:
1940     res = nmsg_message_enum_name_to_value(THIS, field, name, &value);
1941     if (res == nmsg_res_success)
1942         mXPUSHu(value);
1943 
1944 void
1945 enum_name_to_value_by_idx(THIS, f_idx, name)
1946     Net::Nmsg::XS::msg  THIS
1947     unsigned            f_idx
1948     const char         *name
1949     PREINIT:
1950     nmsg_res    res;
1951     unsigned    value;
1952     PPCODE:
1953     res = nmsg_message_enum_name_to_value_by_idx(THIS, f_idx, name, &value);
1954     if (res == nmsg_res_success)
1955         mXPUSHu(value);
1956 
1957 void
1958 enum_value_to_name(THIS, field, value)
1959     Net::Nmsg::XS::msg  THIS
1960     const char         *field
1961     unsigned            value
1962     PREINIT:
1963     nmsg_res    res;
1964     const char *name;
1965     PPCODE:
1966     res = nmsg_message_enum_value_to_name(THIS, field, value, &name);
1967     if (res == nmsg_res_success)
1968         mXPUSHs(newSVpv(name, 0));
1969 
1970 void
1971 enum_value_to_name_by_idx(THIS, f_idx, value)
1972     Net::Nmsg::XS::msg  THIS
1973     unsigned            f_idx
1974     unsigned            value
1975     PREINIT:
1976     nmsg_res    res;
1977     const char *name;
1978     PPCODE:
1979     res = nmsg_message_enum_value_to_name_by_idx(THIS, f_idx, value, &name);
1980     if (res == nmsg_res_success)
1981         mXPUSHs(newSVpv(name, 0));
1982 
1983 void
1984 set_field(THIS, field, v_idx, sv)
1985     Net::Nmsg::XS::msg  THIS
1986     const char         *field
1987     unsigned            v_idx
1988     SV                 *sv
1989     PREINIT:
1990     nmsg_res                res;
1991     nmsg_msgmod_field_type  type;
1992     nmsg_field_val_u        data;
1993     uint8_t                *bp;
1994     size_t                  len;
1995     CODE:
1996     res = nmsg_message_get_field_type(THIS, field, &type);
1997     if (res == nmsg_res_success) {
1998         bp = _xs_sv_to_field(aTHX_ sv, type, &data, &len);
1999         res = nmsg_message_set_field(THIS, field, v_idx, bp, len);
2000         if (res != nmsg_res_success)
2001             croak("nmsg_message_set_field failed: %s", nmsg_res_lookup(res));
2002     }
2003     else
2004         croak("nmsg_message_get_field_type failed: %s", nmsg_res_lookup(res));
2005 
2006 void
2007 set_field_by_idx(THIS, f_idx, v_idx, sv)
2008     Net::Nmsg::XS::msg  THIS
2009     unsigned            f_idx
2010     unsigned            v_idx
2011     SV                 *sv;
2012     PREINIT:
2013     nmsg_res                res;
2014     nmsg_msgmod_field_type  type;
2015     nmsg_field_val_u        data;
2016     uint8_t                *bp;
2017     size_t                  len;
2018     CODE:
2019     res = nmsg_message_get_field_type_by_idx(THIS, f_idx, &type);
2020     if (res == nmsg_res_success) {
2021         bp = _xs_sv_to_field(aTHX_ sv, type, &data, &len);
2022         res = nmsg_message_set_field_by_idx(THIS, f_idx, v_idx, bp, len);
2023         if (res != nmsg_res_success)
2024             croak("nmsg_message_set_field_by_idx failed: %s",
2025                   nmsg_res_lookup(res));
2026     }
2027     else
2028         croak("nmsg_message_get_field_type_by_idx failed: %s",
2029               nmsg_res_lookup(res));
2030 
2031 void
2032 nmsg_message_set_source(THIS, source)
2033     Net::Nmsg::XS::msg  THIS
2034     uint32_t            source
2035 
2036 void
2037 nmsg_message_set_operator(THIS, operator)
2038     Net::Nmsg::XS::msg  THIS
2039     uint32_t            operator
2040 
2041 void
2042 nmsg_message_set_group(THIS, group)
2043     Net::Nmsg::XS::msg  THIS
2044     uint32_t            group
2045 
2046 void
2047 set_time(THIS, time_sec, time_nsec)
2048     Net::Nmsg::XS::msg  THIS
2049     long                time_sec
2050     int                 time_nsec
2051     PREINIT:
2052     struct timespec ts;
2053     PPCODE:
2054     ts.tv_sec = time_sec;
2055     ts.tv_nsec = time_nsec;
2056     nmsg_message_set_time(THIS, &ts);
2057 
2058 void
2059 message_to_pres(THIS, endline)
2060     Net::Nmsg::XS::msg    THIS
2061     const char           *endline
2062     PREINIT:
2063     nmsg_res  res;
2064     char     *pres;
2065     PPCODE:
2066     pthread_mutex_lock(&presentation_lock);
2067     res = nmsg_message_to_pres(THIS, &pres, endline);
2068     if (res != nmsg_res_success)
2069         goto out;
2070     mXPUSHs(newSVpv(pres, 0));
2071     Safefree(pres);
2072     out:
2073     pthread_mutex_unlock(&presentation_lock);
2074     if (res != nmsg_res_success)
2075         croak("nmsg_message_to_pres failed: %s", nmsg_res_lookup(res));
2076 
2077 void
2078 get_field_type_descr_by_idx(THIS, f_idx)
2079     Net::Nmsg::XS::msg  THIS
2080     unsigned            f_idx
2081     PREINIT:
2082     nmsg_res                res;
2083     nmsg_msgmod_field_type  type;
2084     PPCODE:
2085     res = nmsg_message_get_field_type_by_idx(THIS, f_idx, &type);
2086     if (res == nmsg_res_success) {
2087         mXPUSHs(newSViv(type));
2088 
2089         switch (type) {
2090 
2091         case nmsg_msgmod_ft_enum:
2092             mXPUSHs(newSVpvs("enum"));
2093             break;
2094         case nmsg_msgmod_ft_int16:
2095             mXPUSHs(newSVpvs("int16"));
2096             break;
2097         case nmsg_msgmod_ft_int32:
2098             mXPUSHs(newSVpvs("int32"));
2099             break;
2100         case nmsg_msgmod_ft_uint16:
2101             mXPUSHs(newSVpvs("uint16"));
2102             break;
2103         case nmsg_msgmod_ft_uint32:
2104             mXPUSHs(newSVpvs("uint32"));
2105             break;
2106         case nmsg_msgmod_ft_uint64:
2107             mXPUSHs(newSVpvs("uint64"));
2108             break;
2109         case nmsg_msgmod_ft_int64:
2110             mXPUSHs(newSVpvs("int64"));
2111             break;
2112         case nmsg_msgmod_ft_string:
2113             mXPUSHs(newSVpvs("string"));
2114             break;
2115         case nmsg_msgmod_ft_mlstring:
2116             mXPUSHs(newSVpvs("mlstring"));
2117             break;
2118         case nmsg_msgmod_ft_bytes:
2119             mXPUSHs(newSVpvs("bytes"));
2120             break;
2121         case nmsg_msgmod_ft_ip:
2122             mXPUSHs(newSVpvs("ip"));
2123             break;
2124         default:
2125             mXPUSHs(newSVpvs("unknown"));
2126         }
2127     }
2128 
2129 void
2130 get_field_flag_descr_by_idx(THIS, f_idx)
2131     Net::Nmsg::XS::msg  THIS
2132     unsigned            f_idx
2133     PREINIT:
2134     nmsg_res    res;
2135     unsigned    flags;
2136     PPCODE:
2137     res = nmsg_message_get_field_flags_by_idx(THIS, f_idx, &flags);
2138     if (res == nmsg_res_success) {
2139         if (flags & NMSG_FF_REPEATED)
2140             mXPUSHs(newSViv(NMSG_FF_REPEATED));
2141             mXPUSHs(newSVpvs("repeated"));
2142         if (flags & NMSG_FF_REQUIRED)
2143             mXPUSHs(newSViv(NMSG_FF_REQUIRED));
2144             mXPUSHs(newSVpvs("required"));
2145         if (flags & NMSG_FF_HIDDEN)
2146             mXPUSHs(newSViv(NMSG_FF_HIDDEN));
2147             mXPUSHs(newSVpvs("hidden"));
2148         if (flags & NMSG_FF_NOPRINT)
2149             mXPUSHs(newSViv(NMSG_FF_NOPRINT));
2150             mXPUSHs(newSVpvs("noprint"));
2151     }
2152 
2153 void
2154 get_field_enum_descr_by_idx(THIS, f_idx)
2155     Net::Nmsg::XS::msg  THIS
2156     unsigned            f_idx
2157     PREINIT:
2158     nmsg_res                res;
2159     nmsg_msgmod_field_type  type;
2160     unsigned                v;
2161     const char             *name;
2162     PPCODE:
2163     res = nmsg_message_get_field_type_by_idx(THIS, f_idx, &type);
2164     if (res == nmsg_res_success && type == nmsg_msgmod_ft_enum) {
2165         for (v = 0;  ; v++) {
2166             res = nmsg_message_enum_value_to_name_by_idx(
2167                     THIS, f_idx, v, &name);
2168             if (res != nmsg_res_success)
2169                 break;
2170             mXPUSHu(v);
2171             mXPUSHs(newSVpv(name, 0));
2172         }
2173     }
2174