in reply to XS question: typemap for a pointer to a pointer?

You need a typemap for "u_char *" (just the one "*") and use "u_char * &buf" as the declaration for the argument.

This is from fuzzy memory so let me know if that worked.

        - tye (but my friends call me "Tye")
  • Comment on (tye)Re: XS question: typemap for a pointer to a pointer?

Replies are listed 'Best First'.
Re: (tye)Re: XS question: typemap for a pointer to a pointer?
by Big Willy (Scribe) on Apr 11, 2001 at 01:41 UTC
    I made the changes as you suggested. My XS file now reads:
    int libnet_init_packet(p_size, buf) size_t p_size u_char * & buf OUTPUT: buf
    I also did the same thing for libnet_destory_packet(). It now compiles as I hoped it would, but I get a memory fault when I run this test script:
    # Before `make install' is performed this script should be runnable wi +th # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on f +ailure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) BEGIN { $| = 1; print "1..1\n"; } END {print "not ok 1\n" unless $loaded;} use Net::LibnetRaw; $loaded = 1; print "ok 1\n"; my $buf; Net::LibnetRaw::libnet_init_packet(IP_H, $buf); my $dip = Net::LibnetRaw::libnet_name_resolve("10.0.0.4", 1); my $sip = Net::LibnetRaw::libnet_name_resolve("10.0.0.1", 1); #my $sock = Net::LibnetRaw::libnet_open_raw_sock(IPPROTO_RAW); Net::LibnetRaw::libnet_build_ip(ICMP_ECHO_H, 0, 12345, 0, 127, 0, $sip +, $dip, undef, 0, $buf); Net::LibnetRaw::libnet_write_ip($sock, $buf, IP_H + ICMP_ECHO_H); Net::LibnetRaw::libnet_close_raw_sock($sock); Net::LibnetRaw::libnet_destroy_packet($buf); ######################### End of black magic. # Insert your test code below (better if it prints "ok 13" # (correspondingly "not ok 13") depending on the success of chunk 13 # of the test code):
    It appears that the error occurs when I call libnet_build_ip(). It seems pretty clear that there is an issue with the passage and management of buf. Buf is supposed to come back out by reference here. My XSUB for libnet_build_ip() is:
    int libnet_build_ip(len, tos, id, frag, ttl, prot, saddr, daddr, payload, +payload_s, buf) u_short len u_char tos u_short id u_short frag u_char ttl u_char prot u_long saddr u_long daddr const u_char * payload int payload_s u_char & buf OUTPUT: buf
    It is appropriate for the function prototype. buf is not passed as a C "u_char **" like with libnet_init_packet(). buf should be holding a C pointer to the meory location allocated by libnet_packet_init(), which is basically a wrapper to malloc() which passed the buf back by reference.

    My guess is that there is some issue related to storing a pointer to a memory location used in C in a perl reference. If my guess is correction, how do I work around this? If not, then what the hell am I doing wrong? I've considered writing additional C code to simply allow $buf to hold a number which would act sort of like a "buffer descriptor" ala UNIX file I/O and keep the pointers in perl, but I really want to do as much of this in perl as possible.

    Your solutions are greatly appreciated.

      Can you post the generated C code that relates to the processing of the problem argument (near the top and bottom of each generated subroutine)? You want the pointer to be stashed as an opaque value (usually an unsigned long integer, UV). If you have the typemap class wrong then the C code might be trying to copy the data in the allocated buffer rather than just stashing the pointer's value.

      I don't recall which typemap class is meant to do this and looking at the generated C code prevents me from having to assembly the pieces myself and possible get confused in the process (I'm often easily confused).

              - tye (but my friends call me "Tye")
        This what you're asking for?
        /* * This file was generated automatically by xsubpp version 1.9507 from + the * contents of LibnetRaw.xs. Do not edit this file, edit LibnetRaw.xs +instead. * * ANY CHANGES MADE HERE WILL BE LOST! * */ #line 1 "LibnetRaw.xs" #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "libnet.h" #line 17 "LibnetRaw.c" XS(XS_Net__LibnetRaw_libnet_open_raw_sock) { dXSARGS; if (items != 1) Perl_croak(aTHX_ "Usage: Net::LibnetRaw::libnet_open_raw_sock( +protocol)"); { int protocol = (int)SvIV(ST(0)); int RETVAL; dXSTARG; RETVAL = libnet_open_raw_sock(protocol); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } XS(XS_Net__LibnetRaw_libnet_close_raw_sock) { dXSARGS; if (items != 1) Perl_croak(aTHX_ "Usage: Net::LibnetRaw::libnet_close_raw_sock +(fd)"); { int fd = (int)SvIV(ST(0)); int RETVAL; dXSTARG; RETVAL = libnet_close_raw_sock(fd); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } XS(XS_Net__LibnetRaw_libnet_write_ip) { dXSARGS; if (items != 3) Perl_croak(aTHX_ "Usage: Net::LibnetRaw::libnet_write_ip(sock, + packet, len)"); { int sock = (int)SvIV(ST(0)); u_char * packet = (u_char *)SvPV(ST(1),PL_na); int len = (int)SvIV(ST(2)); int RETVAL; dXSTARG; RETVAL = libnet_write_ip(sock, packet, len); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } XS(XS_Net__LibnetRaw_libnet_do_checksum) { dXSARGS; if (items != 3) Perl_croak(aTHX_ "Usage: Net::LibnetRaw::libnet_do_checksum(bu +f, protocol, len)"); { u_char buf = (u_char)SvUV(ST(0)); int protocol = (int)SvIV(ST(1)); int len = (int)SvIV(ST(2)); int RETVAL; dXSTARG; RETVAL = libnet_do_checksum(&buf, protocol, len); sv_setuv(ST(0), (UV)buf); SvSETMAGIC(ST(0)); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } XS(XS_Net__LibnetRaw_libnet_init_packet) { dXSARGS; if (items != 2) Perl_croak(aTHX_ "Usage: Net::LibnetRaw::libnet_init_packet(p_ +size, buf)"); { size_t p_size = (size_t)SvIV(ST(0)); u_char * buf = (u_char *)SvPV(ST(1),PL_na); int RETVAL; dXSTARG; RETVAL = libnet_init_packet(p_size, &buf); sv_setpv((SV*)ST(1), buf); SvSETMAGIC(ST(1)); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } XS(XS_Net__LibnetRaw_libnet_destroy_packet) { dXSARGS; if (items != 1) Perl_croak(aTHX_ "Usage: Net::LibnetRaw::libnet_destroy_packet +(buf)"); { u_char * buf = (u_char *)SvPV(ST(0),PL_na); int RETVAL; dXSTARG; RETVAL = libnet_destroy_packet(&buf); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } XS(XS_Net__LibnetRaw_libnet_name_resolve) { dXSARGS; if (items != 2) Perl_croak(aTHX_ "Usage: Net::LibnetRaw::libnet_name_resolve(h +ostname, use_name)"); { u_char * hostname = (u_char *)SvPV(ST(0),PL_na); u_short use_name = (u_short)SvUV(ST(1)); u_long RETVAL; dXSTARG; RETVAL = libnet_name_resolve(hostname, use_name); XSprePUSH; PUSHu((UV)RETVAL); } XSRETURN(1); } XS(XS_Net__LibnetRaw_libnet_build_ip) { dXSARGS; if (items != 11) Perl_croak(aTHX_ "Usage: Net::LibnetRaw::libnet_build_ip(len, +tos, id, frag, ttl, prot, saddr, daddr, payload, payload_s, buf)"); { u_short len = (u_short)SvUV(ST(0)); u_char tos = (u_char)SvUV(ST(1)); u_short id = (u_short)SvUV(ST(2)); u_short frag = (u_short)SvUV(ST(3)); u_char ttl = (u_char)SvUV(ST(4)); u_char prot = (u_char)SvUV(ST(5)); u_long saddr = (u_long)SvUV(ST(6)); u_long daddr = (u_long)SvUV(ST(7)); const u_char * payload = (const u_char *)SvPV(ST(8),PL_na); int payload_s = (int)SvIV(ST(9)); u_char buf = (u_char)SvUV(ST(10)); int RETVAL; dXSTARG; RETVAL = libnet_build_ip(len, tos, id, frag, ttl, prot, saddr, + daddr, payload, payload_s, &buf); sv_setuv(ST(10), (UV)buf); SvSETMAGIC(ST(10)); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } XS(XS_Net__LibnetRaw_libnet_build_tcp) { dXSARGS; if (items != 10) Perl_croak(aTHX_ "Usage: Net::LibnetRaw::libnet_build_tcp(spor +t, dport, seq, ack, control, win, urg, payload, payload_s, buf)"); { u_short sport = (u_short)SvUV(ST(0)); u_short dport = (u_short)SvUV(ST(1)); u_long seq = (u_long)SvUV(ST(2)); u_long ack = (u_long)SvUV(ST(3)); u_char control = (u_char)SvUV(ST(4)); u_short win = (u_short)SvUV(ST(5)); u_short urg = (u_short)SvUV(ST(6)); const u_char * payload = (const u_char *)SvPV(ST(7),PL_na); int payload_s = (int)SvIV(ST(8)); u_char buf = (u_char)SvUV(ST(9)); int RETVAL; dXSTARG; RETVAL = libnet_build_tcp(sport, dport, seq, ack, control, win +, urg, payload, payload_s, &buf); sv_setuv(ST(9), (UV)buf); SvSETMAGIC(ST(9)); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); } #ifdef __cplusplus extern "C" #endif XS(boot_Net__LibnetRaw) { dXSARGS; char* file = __FILE__; XS_VERSION_BOOTCHECK ; newXS("Net::LibnetRaw::libnet_open_raw_sock", XS_Net__LibnetRa +w_libnet_open_raw_sock, file); newXS("Net::LibnetRaw::libnet_close_raw_sock", XS_Net__LibnetR +aw_libnet_close_raw_sock, file); newXS("Net::LibnetRaw::libnet_write_ip", XS_Net__LibnetRaw_lib +net_write_ip, file); newXS("Net::LibnetRaw::libnet_do_checksum", XS_Net__LibnetRaw_ +libnet_do_checksum, file); newXS("Net::LibnetRaw::libnet_init_packet", XS_Net__LibnetRaw_ +libnet_init_packet, file); newXS("Net::LibnetRaw::libnet_destroy_packet", XS_Net__LibnetR +aw_libnet_destroy_packet, file); newXS("Net::LibnetRaw::libnet_name_resolve", XS_Net__LibnetRaw +_libnet_name_resolve, file); newXS("Net::LibnetRaw::libnet_build_ip", XS_Net__LibnetRaw_lib +net_build_ip, file); newXS("Net::LibnetRaw::libnet_build_tcp", XS_Net__LibnetRaw_li +bnet_build_tcp, file); XSRETURN_YES; }
        Just for concenience, the typemap:
        u_char * T_PV u_char T_UV u_short T_UV u_long T_UV const u_char * T_PV
        Perhaps I am thinking of a pointer to a pointer in the wrong fashion or I am confusing the ways in which perl reference work that I am not clear on. I truly appreciate your help!