ph713 has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks. I'm on my 2nd day of learning XS here, and I can't seem to find any docs or examples on something I'm trying to get done here. On the C side of my code, I have a file descriptor (an integer), which is already open and working (actually it's not just any file descriptor, it's specifically a socket, but lets get there one step at a time). I want to make a callback to a perl function using call_sv(), and I want this file descriptor to appear as one of the callback arguments, in the form of a normal perl filehandle.

At one point, I was just passing the raw file descriptor into the perl callback as an integer, like so:

int conn = socket(.....); [...] ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSViv(conn))); PUTBACK; cpretval = call_sv(the_coderef, G_SCALAR|G_EVAL|G_KEEPERR); SPAGAIN; if(SvTRUE(ERRSV)) { STRLEN n_a; log_helper(1,kidno,SvPV(ERRSV, n_a)); POPs; real_retval = 0; } else { if(cpretval != 1) croak("Return count from coderef callback != 1"); real_retval = POPi; } PUTBACK; FREETMPS; LEAVE;
And then in the called-back perl code being called, I did:
sub the_callback_function { my ($conn) = @_; open(my $c,"+<&=$conn"); bless $c, 'IO::Socket::INET'; $c->autoflush(1); $c->send("Network data!\n"); .....

And surprisingly that worked fine, and sent "Network data!\n" out over the open socket. I'm sure there are some grave issues lurking in my heathen blessing of the filehandle to IO::Socket::INET without using any of its constructor code if I started using some of the other methods, but that's not terribly important at the moment.

So my next step was to eliminate the neccesity of having the perl side of things use that funky open(my $c,"+<&=$conn"); line by having the C code send an actual perl filehandle instead of a raw integer. I've gotten halfway there (I think), by creating a PerlIO* out of my integer in C, using:

PerlIO* conn_pio; conn_pio = PerlIO_fdopen(conn,"r+");
However, attempting to do things like XPUSHs((SV*)conn_pio) are of course failing to do jack. How exactly does one properly push a PerlIO object onto the argument stack? It seems like there should be a function like io_2sv() to match the one I found named sv_2io(), but I don't see it, or anything that looks like it. Any ideas?

Replies are listed 'Best First'.
Re: Sending PerlIO* to the stack for call_sv()?
by ph713 (Pilgrim) on Oct 16, 2005 at 05:37 UTC
    Update: I've managed to get it working - the C code now passes in a real filehandle glob which is already blessed to IO::Socket::INET. However, I'm not entirely sure that my code to do so is entirely sane and correct. It's more or less what I managed to cobble together by reading the source to pp_socket in pp_sys.c and staring at the perlapi/perlguts/etc docs. I don't entirely understand the purpose of some things, and I'm not sure that I'm not leaking memory:
    [...] IO* conn_pio; SV* connrv; GV* fhglob; HV* our_stash; HV* isn_stash; isn_stash = gv_stashpv("IO::Socket::INET",1); our_stash = gv_stashpv("MyModule::Name",1); fhglob = gv_fetchmethod(our_stash,"myfilehandle"); conn_pio = GvIOn(fhglob); IoIFP(conn_pio) = PerlIO_fdopen(conn, "r"SOCKET_OPEN_MODE); IoOFP(conn_pio) = PerlIO_fdopen(conn, "w"SOCKET_OPEN_MODE); IoTYPE(conn_pio) = IoTYPE_SOCKET; connrv = newRV_inc((SV*)fhglob); sv_bless(connrv,isn_stash); ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(connrv); PUTBACK; cpretval = call_sv(kid_conn_coderef, G_SCALAR|G_EVAL|G_KEEPERR); [....]
Re: Sending PerlIO* to the stack for call_sv()?
by Anonymous Monk on Oct 16, 2005 at 10:36 UTC
      Doesn't work for PerlIO objects. Compiler throws warning of wrong pointer type, and the perl function ends up receiving "undef" in place of where the PerlIO argument should have been.
        A PerlIO* isn't a scalar, so you can't put it on the stack. FYI, to get a PerlIO* from a filehandle created in Perl, you use...

        PerlIO* outstream = IoOFP( sv_2io(out_fh_ref_sv) ); PerlIO* instream = IoIFP( sv_2io(in_fh_ref_sv) );

        Note that IoOFP and IoIFP are not officially blessed in perlapi, but people are using them in CPAN code, and it's the only way to get the job done.

        As for going the other way, what you're doing looks right to me, but I'm not a guru.

        --
        Marvin Humphrey
        Rectangular Research ― http://www.rectangular.com