Socket-Class

 view release on metacpan or  search on metacpan

Class.xs  view on Meta::CPAN

#include "socket_class.h"
#include "sc_mod_def.h"

MODULE = Socket::Class		PACKAGE = Socket::Class

#/*****************************************************************************
# * BOOT()
# *****************************************************************************/

BOOT:
{
	HV *stash;
#ifdef SC_DEBUG
	_debug( "INIT called\n" );
#endif
#if SC_DEBUG > 1
	debug_init();
#endif
#ifdef _WIN32
	{
		WSADATA wsaData;
		int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
		if( iResult != NO_ERROR )
			Perl_croak( aTHX_ "Error at WSAStartup()" );
	}
#endif
	Zero( &sc_global, 1, sc_global_t );
	sc_global.process_id = PROCESS_ID();
#ifdef USE_ITHREADS
	MUTEX_INIT( &sc_global.thread_lock );
#endif
	stash = gv_stashpvn( __PACKAGE__, (I32) sizeof(__PACKAGE__), FALSE );
#ifdef SC_OLDNET
	newCONSTSUB( stash, "OLDNET", newSViv( 1 ) );
#else
	newCONSTSUB( stash, "OLDNET", newSViv( 0 ) );
#endif
#ifdef SC_HAS_BLUETOOTH
	newCONSTSUB( stash, "BLUETOOTH", newSViv( 1 ) );
	boot_Socket__Class__BT();
#else
	newCONSTSUB( stash, "BLUETOOTH", newSViv( 0 ) );
#endif
	/* store the c module interface in the modglobal hash */
	(void) hv_store( PL_modglobal,
		"Socket::Class", 13, newSViv( PTR2IV( &mod_sc ) ), 0 );
}


#/*****************************************************************************
# * c_module()
# *****************************************************************************/
void
c_module( ... )
PPCODE:
	/* returns the c module interface */
	XSRETURN_IV( PTR2IV( &mod_sc ) );


#/*****************************************************************************
# * END()
# *****************************************************************************/

void
END( ... )
PREINIT:
	socket_class_t *sc1, *sc2;
	int i;
CODE:
	(void) items; /* avoid compiler warning */
	if( sc_global.destroyed || PROCESS_ID() != sc_global.process_id )
		return;
	sc_global.destroyed = 1;
#ifdef SC_DEBUG
	_debug( "END called\n" );
#endif
	GLOBAL_LOCK();
	for( i = 0; i <= SC_CASCADE; i ++ ) {
		sc1 = sc_global.socket[i];
		while( sc1 != NULL ) {
			sc2 = sc1->next;
			socket_class_free( sc1 );
			sc1 = sc2;
		}
		sc_global.socket[i] = NULL;
	}
	GLOBAL_UNLOCK();
#ifdef USE_ITHREADS
	MUTEX_DESTROY( &sc_global.thread_lock );
#endif
#ifdef _WIN32
	WSACleanup();
#endif
#if SC_DEBUG > 1
	debug_free();
#endif


#/*****************************************************************************
# * CLONE()
# *****************************************************************************/

#ifdef USE_ITHREADS

void
CLONE( ... )
PREINIT:
	socket_class_t *sc;
	int i;
PPCODE:
	GLOBAL_LOCK();
	for( i = 0; i <= SC_CASCADE; i ++ ) {
		for( sc = sc_global.socket[i]; sc != NULL; sc = sc->next ) {
			if( sc->do_clone )
				sc->refcnt ++;
#ifdef SC_DEBUG
			_debug( "CLONE called for sc %lu refcnt: %d\n", sc->id, sc->refcnt );
#endif
		}
	}
	GLOBAL_UNLOCK();

#endif


#/*****************************************************************************
# * DESTROY( this )
# *****************************************************************************/

void
DESTROY( this, ... )
	SV *this;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
#ifdef SC_DEBUG
	_debug( "DESTROY called for sc %lu refcnt: %d\n", sc->id, sc->refcnt - 1 );
#endif
#ifdef USE_ITHREADS
	if( sc->do_clone && sc->thread_id == THREAD_ID() ) {
		sc->do_clone = FALSE;
#ifdef SC_DEBUG
		_debug( "Disabled futher CLONE for sc %lu\n", sc->id );
#endif
	}
#endif
	mod_sc_refcnt_dec( sc );


#/*****************************************************************************
# * new( class )
# *****************************************************************************/

void
new( class, ... )
	SV *class;
PREINIT:
	socket_class_t *sc;
	char **args;
	int argc = 0, r, i;
	SV *sv;
PPCODE:
	Newx( args, items - 1, char * );
	/* read options */
	for( i = 1; i < items - 1; ) {
		args[argc ++] = SvPV_nolen( ST(i) );
		i ++;
		args[argc ++] = SvPV_nolen( ST(i) );
		i ++;
	}
	r = mod_sc_create( args, argc, &sc );
	Safefree( args );
	if( r != SC_OK )
		XSRETURN_EMPTY;
	/* create the class */
	r = mod_sc_create_class( sc, SvPV_nolen( class ), &sv );
	if( r != SC_OK ) {
		mod_sc_set_error( NULL, sc->last_errno, sc->last_error );
		mod_sc_destroy( sc );
		XSRETURN_EMPTY;
	}
	ST(0) = sv_2mortal( sv );
	XSRETURN(1);


#/*****************************************************************************
# * connect( this )
# *****************************************************************************/

void
connect( this, ... )
	SV *this;
PREINIT:
	socket_class_t *sc;
	const char *s1 = NULL, *s2 = NULL;
	double ms = 0;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	switch( sc->s_domain ) {
	case AF_INET:
	case AF_INET6:
	default:
		switch( items ) {
		case 4:
		default:
			if( SvNOK( ST(3) ) || SvIOK( ST(3) ) )
				ms = SvNV( ST(3) );
		case 3:
			s1 = SvPV_nolen( ST(1) );
			s2 = SvPV_nolen( ST(2) );
			break;
		case 2:
			s1 = SvPV_nolen( ST(1) );
			break;
		}
		break;
	case AF_UNIX:
		switch( items ) {
		case 3:
		default:
			if( SvNOK( ST(2) ) || SvIOK( ST(2) ) )
				ms = SvNV( ST(2) );
		case 2:
			s1 = SvPV_nolen( ST(1) );
			break;
		}
		break;
	}
	if( mod_sc_connect( sc, s1, s2, ms ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * free( this )
# *****************************************************************************/

void
free( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	mod_sc_destroy( sc );
	XSRETURN_YES;


#/*****************************************************************************
# * close( this )
# *****************************************************************************/

void
close( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = socket_class_find( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_close( sc ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * shutdown( this )
# *****************************************************************************/

void
shutdown( this, how = 0 )
	SV *this;
	int how
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = socket_class_find( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_shutdown( sc, how ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * bind( this )
# *****************************************************************************/

void
bind( this, addr = NULL, port = NULL )
	SV *this;
	char *addr;
	char *port;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_bind( sc, addr, port ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * listen( this )
# *****************************************************************************/

void
listen( this, queue = SOMAXCONN )
	SV *this;
	int queue;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_listen( sc, queue < 0 ? SOMAXCONN : queue ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * accept( this )
# *****************************************************************************/

void
accept( this, pkg = NULL )
	SV *this;
	char *pkg;
PREINIT:
	socket_class_t *sc, *sc2;
	SV *sv;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_accept( sc, &sc2 ) != SC_OK )
		XSRETURN_EMPTY;
	if( sc2 == NULL )
		XSRETURN_NO;
	if( mod_sc_create_class( sc2, pkg, &sv ) != SC_OK ) {
		mod_sc_destroy( sc2 );
		XSRETURN_EMPTY;
	}
	ST(0) = sv_2mortal( sv );
	XSRETURN(1);


#/*****************************************************************************
# * recv( this, buf, len [, flags] )
# *****************************************************************************/

void
recv( this, buf, len, flags = 0 )
	SV *this;
	SV *buf;
	unsigned int len;
	unsigned int flags;
PREINIT:
	socket_class_t *sc;
	int rlen;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( sc->buffer_len < len ) {
		sc->buffer_len = len;
		Renew( sc->buffer, len, char );
	}
	if( mod_sc_recv( sc, sc->buffer, len, flags, &rlen ) != SC_OK )
		XSRETURN_EMPTY;
	if( rlen == 0 )
		XSRETURN_NO;
	sv_setpvn( buf, sc->buffer, rlen );
	XSRETURN_IV( rlen );


#/*****************************************************************************
# * send( this, buf [, flags] )
# *****************************************************************************/

void
send( this, buf, flags = 0 )
	SV *this;
	SV *buf;
	unsigned int flags;
PREINIT:
	socket_class_t *sc;
	const char *msg;
	STRLEN len;
	int rlen;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	msg = SvPV( buf, len );
	if( mod_sc_send( sc, msg, (int) len, flags, &rlen ) != SC_OK )
		XSRETURN_EMPTY;
	if( rlen == 0 )
		XSRETURN_NO;
	XSRETURN_IV( rlen );


#/*****************************************************************************
# * recvfrom( this, buf, len [, flags] )
# *****************************************************************************/

void
recvfrom( this, buf, len, flags = 0 )
	SV *this;
	SV *buf;
	size_t len;
	unsigned int flags;
PREINIT:
	socket_class_t *sc;
	int rlen;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( sc->buffer_len < len ) {
		sc->buffer_len = len;
		Renew( sc->buffer, len, char );
	}
	if( mod_sc_recvfrom( sc, sc->buffer, (int) len, flags, &rlen ) != SC_OK )
		XSRETURN_EMPTY;
	if( rlen == 0 )
		XSRETURN_NO;
	sv_setpvn( buf, sc->buffer, rlen );
	ST(0) = sv_2mortal( newSVpvn(
		(char *) &sc->r_addr, SC_ADDR_SIZE( sc->r_addr ) ) );
	XSRETURN(1);


#/*****************************************************************************
# * sendto( this, buf [, to [, flags]] )
# *****************************************************************************/

void
sendto( this, buf, to = NULL, flags = 0 )
	SV *this;
	SV *buf;
	SV *to;
	unsigned int flags;
PREINIT:
	socket_class_t *sc;
	const char *msg;
	STRLEN len;
	sc_addr_t *peer = NULL;
	int rlen;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( to != NULL && SvPOK( to ) ) {
		peer = (my_sockaddr_t *) SvPVbyte( to, len );
		if( len < sizeof( int ) || len != SC_ADDR_SIZE(*peer) ) {
			my_snprintf_(
				sc->last_error, sizeof( sc->last_error ),
				"Invalid address"
			);
			XSRETURN_EMPTY;
		}
	}
	msg = SvPV( buf, len );
	if( mod_sc_sendto( sc, msg, (int) len, flags, peer, &rlen ) != SC_OK )
		XSRETURN_EMPTY;
	if( rlen == 0 )
		XSRETURN_NO;
	XSRETURN_IV( rlen );


#/*****************************************************************************
# * read( this, buf, len )
# *****************************************************************************/

void
read( this, buf, len )
	SV *this;
	SV *buf;
	unsigned int len;
PREINIT:
	socket_class_t *sc;
	int rlen;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( sc->buffer_len < len ) {
		sc->buffer_len = len;
		Renew( sc->buffer, len, char );
	}
	if( mod_sc_read( sc, sc->buffer, len, &rlen ) != SC_OK )
		XSRETURN_EMPTY;
	if( rlen == 0 )
		XSRETURN_NO;
	sv_setpvn( buf, sc->buffer, rlen );
	XSRETURN_IV( rlen );


#/*****************************************************************************
# * write( this, buf [, start [, length]] )
# *****************************************************************************/

void
write( this, buf, ... )
	SV *this;
	SV *buf;
PREINIT:
	socket_class_t *sc;
	const char *msg;
	STRLEN l1;
	int start = 0, len, max, l2;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	msg = SvPVx( buf, l1 );
	max = len = (int) l1;
	if( items > 2 ) {
		start = (int) SvIV( ST(2) );
		if( start < 0 ) {
			start += max;
			if( start < 0 )
				start = 0;
		}
		else if( start >= max )
			XSRETURN_IV( 0 );
	}
	if( items > 3 ) {
		l2 = (int) SvIV( ST(3) );
		if( l2 < 0 )
			len += l2;
		else if( l2 < len )
			len = l2;
	}
	if( start + len > max )
		len = max - start;
	if( len <= 0 )
		XSRETURN_IV( 0 );
	if( mod_sc_write( sc, msg + start, len, &len ) != SC_OK )
		XSRETURN_EMPTY;
	if( len == 0 )
		XSRETURN_NO;
	XSRETURN_IV( len );


#/*****************************************************************************
# * readline( this [, separator [, maxsize]] )
# *****************************************************************************/

void
readline( this, separator = NULL, maxsize = 0 )
	SV *this;
	char *separator;
	int maxsize;
PREINIT:
	socket_class_t *sc;
	int rlen, r;
	char *rbuf;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( separator != NULL ) {
		r = mod_sc_read_packet(
			sc, separator, (size_t) maxsize, &rbuf, &rlen );
		if( r != SC_OK )
			XSRETURN_EMPTY;
	}
	else {
		if( mod_sc_readline( sc, &rbuf, &rlen ) != SC_OK )
			XSRETURN_EMPTY;
	}
	ST(0) = sv_2mortal( newSVpvn( rbuf, rlen ) );
	XSRETURN(1);


#/*****************************************************************************
# * writeline( this, buf )
# *****************************************************************************/

void
writeline( this, buf )
	SV *this;
	SV *buf;
PREINIT:
	socket_class_t *sc;
	const char *msg;
	STRLEN len;
	int rlen;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	msg = SvPVx( buf, len );
	if( mod_sc_writeln( sc, msg, (int) len, &rlen ) != SC_OK )
		XSRETURN_EMPTY;
	if( rlen == 0 )
		XSRETURN_NO;
	XSRETURN_IV( rlen );


#/*****************************************************************************
# * print( this )
# *****************************************************************************/

void
print( this, ... )
	SV *this;
PREINIT:
	socket_class_t *sc;
	const char *s1;
	char *tmp = NULL;
	STRLEN l1, len = 0, pos = 0;
	int r, rlen;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	for( r = 1; r < items; r ++ ) {
		if( ! SvOK( ST(r) ) )
			continue;
		s1 = SvPV( ST(r), l1 );
		if( pos + l1 > len ) {
			len = pos + l1 + 64;
			Renew( tmp, len, char );
		}
		Copy( s1, tmp + pos, l1, char );
		pos += l1;
	}
	if( tmp != NULL ) {
		r = mod_sc_write( sc, tmp, (int) pos, &rlen );
		Safefree( tmp );
		if( r != SC_OK )
			XSRETURN_EMPTY;
		if( rlen == 0 )
			XSRETURN_NO;
		XSRETURN_IV( rlen );
	}


#/*****************************************************************************
# * read_packet( this, separator [, maxsize]] )
# *****************************************************************************/

void
read_packet( this, separator, maxsize = 0 )
	SV *this;
	char *separator;
	int maxsize;
PREINIT:
	socket_class_t *sc;
	int rlen, r;
	char *rbuf;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	r = mod_sc_read_packet( sc, separator, (size_t) maxsize, &rbuf, &rlen );
	if( r != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( rbuf, rlen ) );
	XSRETURN(1);


#/*****************************************************************************
# * available( this )
# *****************************************************************************/

void
available( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	int len;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_available( sc, &len ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_IV( (IV) len );


#/*****************************************************************************
# * pack_addr( this, addr [, port] )
# *****************************************************************************/

void
pack_addr( this, addr, ... )
	SV *this;
	SV *addr;
PREINIT:
	socket_class_t *sc;
	my_sockaddr_t saddr;
	char *s1, *s2;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	s1 = SvPV_nolen( addr );
	if( items > 2 )
		s2 = SvPV_nolen( ST(2) );
	else
		s2 = NULL;
	if( mod_sc_pack_addr( sc, s1, s2, &saddr ) != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( (char *) &saddr, SC_ADDR_SIZE(saddr) ) );
	XSRETURN(1);


#/*****************************************************************************
# * unpack_addr( this, paddr )
# *****************************************************************************/

void
unpack_addr( this, paddr )
	SV *this;
	SV *paddr;
PREINIT:
	socket_class_t *sc;
	my_sockaddr_t *saddr;
	STRLEN len;
	char addr[NI_MAXHOST], port[NI_MAXSERV];
	int addr_len = NI_MAXHOST, port_len = NI_MAXSERV, r;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	saddr = (my_sockaddr_t *) SvPVbyte( paddr, len );
	if( len < sizeof( int ) || len != SC_ADDR_SIZE(*saddr) ) {
		my_snprintf_(
			sc->last_error, sizeof( sc->last_error ),
			"Invalid address"
		);
		XSRETURN_EMPTY;
	}
	r = mod_sc_unpack_addr( sc, saddr, addr, &addr_len, port, &port_len );
	if( r != SC_OK )
		XSRETURN_EMPTY;
	XPUSHs( sv_2mortal( newSVpvn( addr, addr_len ) ) );
	if( GIMME_V == G_ARRAY && port_len ) {
		XPUSHs( sv_2mortal( newSVpvn( port, port_len ) ) );
	}
	

#/*****************************************************************************
# * get_hostname( this, addr )
# *****************************************************************************/

void
get_hostname( this, addr = NULL )
	SV *this;
	SV *addr;
PREINIT:
	socket_class_t *sc;
	my_sockaddr_t *saddr, sa2;
	const char *s1 = NULL;
	STRLEN l1;
	char host[NI_MAXHOST];
	int host_len = NI_MAXHOST;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( addr != NULL ) {
		s1 = SvPV( addr, l1 );
		saddr = (my_sockaddr_t *) s1;
		if( l1 <= sizeof( int ) || l1 != SC_ADDR_SIZE(*saddr) ) {
			if( mod_sc_pack_addr( sc, s1, NULL, &sa2 ) != SC_OK )
				XSRETURN_EMPTY;
			saddr = &sa2;
		}
	}
	else {
		saddr = &sc->r_addr;
	}
	if( mod_sc_gethostbyaddr( sc, saddr, host, &host_len ) != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( host, host_len ) );
	XSRETURN(1);


#/*****************************************************************************
# * get_hostaddr( this, name )
# *****************************************************************************/

void
get_hostaddr( this, name )
	SV *this;
	SV *name;
PREINIT:
	socket_class_t *sc;
	char addr[40];
	int addr_len = 40, r;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	r = mod_sc_gethostbyname( sc, SvPV_nolen( name ), addr, &addr_len );
	if( r != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( addr, addr_len ) );
	XSRETURN(1);


#/*****************************************************************************
# * getaddrinfo( this, node, service [, family [, proto [, type [, flags ]]]] )
# *****************************************************************************/

void
getaddrinfo( ... )
PREINIT:
	socket_class_t *sc = NULL;
	int ipos = 0, r;
	sc_addrinfo_t aih;
	sc_addrinfo_t *ail = NULL, *ai;
	const char *host, *service;
	HV *hv;
	char tmp[40];
	my_sockaddr_t saddr;
PPCODE:
	if( items > 0 ) {
		if( (sc = mod_sc_get_socket( ST(0) )) != NULL ) {
			ipos ++;
		}
		else if(
			SvPOK( ST(0) ) &&
			strcmp( SvPV_nolen( ST(0) ), __PACKAGE__ ) == 0
		) {
			ipos ++;
		}
	}
	if( items - ipos < 1 )
		Perl_croak( aTHX_ "Usage: Socket::Class::getaddrinfo(node, ...)" );
	if( SvOK( ST(ipos) ) )
		host = SvPV_nolen( ST(ipos) );
	else
		host = NULL;
	ipos ++;
	if( ipos < items && SvOK( ST(ipos) ) )
		service = SvPV_nolen( ST(ipos) );
	else
		service = "";
	ipos ++;
	memset( &aih, 0, sizeof(sc_addrinfo_t) );
	if( ipos < items ) {
		if( SvIOK( ST(ipos) ) )
			aih.ai_family = (int) SvIV( ST(ipos) );
		else
			aih.ai_family = Socket_domainbyname( SvPV_nolen( ST(ipos) ) );
#ifdef SC_DEBUG
		_debug( "using family %d\n", aih.ai_family );
#endif
		ipos ++;
	}
	if( ipos < items ) {
		if( SvIOK( ST(ipos) ) )
			aih.ai_protocol = (int) SvIV( ST(ipos) );
		else
			aih.ai_protocol = Socket_protobyname( SvPV_nolen( ST(ipos) ) );
#ifdef SC_DEBUG
		_debug( "using protocol %d\n", aih.ai_protocol );
#endif
		ipos ++;
	}
	if( ipos < items ) {
		if( SvIOK( ST(ipos) ) )
			aih.ai_socktype = (int) SvIV( ST(ipos) );
		else
			aih.ai_socktype = Socket_typebyname( SvPV_nolen( ST(ipos) ) );
#ifdef SC_DEBUG
		_debug( "using socktype %d\n", aih.ai_socktype );
#endif
		ipos ++;
	}
#if defined __MVS__ && defined AI_ALL
	/* set AI_ALL on OS390 as default flag */
	if( aih.ai_family == AF_UNSPEC )
		aih.ai_flags = AI_ALL;
#endif
	if( ipos < items ) {

Class.xs  view on Meta::CPAN

			(void) hv_store( hv, "sockname", 8, newSVpvn( "STREAM", 6 ), 0 );
			break;
		case SOCK_DGRAM:
			(void) hv_store( hv, "sockname", 8, newSVpvn( "DGRAM", 5 ), 0 );
			break;
		case SOCK_RAW:
			(void) hv_store( hv, "sockname", 8, newSVpvn( "RAW", 3 ), 0 );
			break;
		case SOCK_RDM:
			(void) hv_store( hv, "sockname", 8, newSVpvn( "RDM", 3 ), 0 );
			break;
		case SOCK_SEQPACKET:
			(void) hv_store( hv, "sockname", 8, newSVpvn( "SEQPACKET", 9 ), 0 );
			break;
		}
		/* protoname */
		switch( ai->ai_family ) {
		case AF_INET:
		case AF_INET6:
			switch( ai->ai_protocol ) {
			case IPPROTO_TCP:
				(void) hv_store( hv, "protoname", 9, newSVpvn( "TCP", 3 ), 0 );
				break;
			case IPPROTO_UDP:
				(void) hv_store( hv, "protoname", 9, newSVpvn( "UDP", 3 ), 0 );
				break;
			case IPPROTO_ICMP:
				(void) hv_store( hv, "protoname", 9, newSVpvn( "ICMP", 4 ), 0 );
				break;
			}
			break;
		case AF_BLUETOOTH:
			switch( ai->ai_protocol ) {
			case BTPROTO_RFCOMM:
				(void) hv_store( hv, "protoname", 9, newSVpvn( "RFCOMM", 6 ), 0 );
				break;
			case BTPROTO_L2CAP:
				(void) hv_store( hv, "protoname", 9, newSVpvn( "L2CAP", 5 ), 0 );
				break;
			}
			break;
		}
		XPUSHs( sv_2mortal( newRV( (SV *) hv ) ) );
	}
	mod_sc_freeaddrinfo( ail );


#/*****************************************************************************
# * getnameinfo( this, addr, port, family, flags )
# *****************************************************************************/

void
getnameinfo( ... )
PREINIT:
	socket_class_t *sc = NULL;
	int ipos = 0, r, family = AF_UNSPEC, flags = 0;
	char host[NI_MAXHOST], serv[NI_MAXSERV], *addr, *port = "";
	my_sockaddr_t saddr, *psaddr;
	sc_addrinfo_t aih, *ail = NULL;
	STRLEN len;
PPCODE:
	if( items > 0 ) {
		if( (sc = mod_sc_get_socket( ST(0) )) != NULL ) {
			ipos ++;
		}
		else if(
			SvPOK( ST(0) ) &&
			strcmp( SvPV_nolen( ST(0) ), __PACKAGE__ ) == 0
		) {
			ipos ++;
		}
	}
	if( items - ipos < 1 )
		Perl_croak( aTHX_ "Usage: Socket::Class::getnameinfo(addr, ...)" );
	psaddr = (my_sockaddr_t *) SvPVbyte( ST(ipos), len );
	if( len > sizeof( int ) && len == SC_ADDR_SIZE(*psaddr) ) {
		/* packed address */
		ipos ++;
		if( ipos < items ) {
			flags = (int) SvIV( ST(ipos) );
			ipos ++;
		}
	}
	else {
		addr = SvPV_nolen( ST(ipos) );
		ipos ++;
		if( ipos < items ) {
			port = SvPV_nolen( ST(ipos) );
			ipos ++;
		}
		if( ipos < items ) {
			if( SvIOK( ST(ipos) ) )
				family = (int) SvIV( ST(ipos) );
			else
				family = Socket_domainbyname( SvPV_nolen( ST(ipos) ) );
			ipos ++;
		}
		if( ipos < items ) {
			flags = (int) SvIV( ST(ipos) );
			ipos ++;
		}
		memset( &aih, 0, sizeof( sc_addrinfo_t ) );
		aih.ai_family = family;
		if( mod_sc_getaddrinfo( sc, addr, port, &aih, &ail ) != SC_OK )
			XSRETURN_EMPTY;
		saddr.l = (socklen_t) ail->ai_addrlen;
		memcpy( saddr.a, ail->ai_addr, ail->ai_addrlen );
		mod_sc_freeaddrinfo( ail );
		psaddr = &saddr;
	}
	r = mod_sc_getnameinfo(
		sc, psaddr, host, sizeof( host ), serv, sizeof( serv ), flags );
	if( r != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( host, strlen( host ) ) );
	if( GIMME_V != G_ARRAY )
		XSRETURN(1);
	ST(1) = sv_2mortal( newSVpvn( serv, strlen( serv ) ) );
	XSRETURN(2);


#/*****************************************************************************
# * set_blocking( this [, bool] )
# *****************************************************************************/

void
set_blocking( this, mode = 1 )
	SV *this;
	int mode;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_set_blocking( sc, mode ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * get_blocking( this )
# *****************************************************************************/

void
get_blocking( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	int mode;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_get_blocking( sc, &mode ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_IV( mode );


#/*****************************************************************************
# * set_reuseaddr( this [, bool] )
# *****************************************************************************/

void
set_reuseaddr( this, mode = 1 )
	SV *this;
	int mode;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_set_reuseaddr( sc, mode ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * get_reuseaddr( this )
# *****************************************************************************/

void
get_reuseaddr( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	int mode;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_get_reuseaddr( sc, &mode ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_IV( mode );


#/*****************************************************************************
# * set_broadcast( this [, bool] )
# *****************************************************************************/

void
set_broadcast( this, mode = 1 )
	SV *this;
	int mode;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_set_broadcast( sc, mode ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * get_broadcast( this )
# *****************************************************************************/

void
get_broadcast( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	int mode;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_get_broadcast( sc, &mode ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_IV( mode );


#/*****************************************************************************
# * set_rcvbuf_size( this, size )
# *****************************************************************************/

void
set_rcvbuf_size( this, size )
	SV *this;
	int size;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_set_rcvbuf_size( sc, size ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * get_rcvbuf_size( this )
# *****************************************************************************/

void
get_rcvbuf_size( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	int size;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_get_rcvbuf_size( sc, &size ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_IV( size );


#/*****************************************************************************
# * set_sndbuf_size( this, size )
# *****************************************************************************/

void
set_sndbuf_size( this, size )
	SV *this;
	int size;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_set_sndbuf_size( sc, size ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * get_sndbuf_size( this )
# *****************************************************************************/

void
get_sndbuf_size( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	int size;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_get_sndbuf_size( sc, &size ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_IV( size );


#/*****************************************************************************
# * set_tcp_nodelay( this [, value] )
# *****************************************************************************/

void
set_tcp_nodelay( this, mode = 1 )
	SV *this;
	int mode;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_set_tcp_nodelay( sc, mode ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * get_tcp_nodelay( this )
# *****************************************************************************/

void
get_tcp_nodelay( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	int mode;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_get_tcp_nodelay( sc, &mode ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_IV( mode );


#/*****************************************************************************
# * set_option( this, level, optname, value )
# *****************************************************************************/

void
set_option( this, level, optname, value, ... )
	SV *this;
	int level;
	int optname;
	SV *value;
PREINIT:
	socket_class_t *sc;
	int r;
	STRLEN len;
	const void *val;
	char tmp[20];
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( SvIOK( value ) && level == SOL_SOCKET ) {
		switch( optname ) {
		case SO_LINGER:
			if( items > 4 ) {
				((struct linger *) tmp)->l_onoff = (uint16_t) SvUV( value );
				((struct linger *) tmp)->l_linger = (uint16_t) SvUV( ST(4) );
			}
			else {
				((struct linger *) tmp)->l_onoff = (uint16_t) SvUV( value );
				((struct linger *) tmp)->l_linger = 1;
			}
			val = tmp;
			len = sizeof( struct linger );
			break;
		case SO_RCVTIMEO:
		case SO_SNDTIMEO:
#ifdef _WIN32
			if( items > 4 ) {
				*((DWORD *) tmp) = (DWORD) SvUV( value ) * 1000;
				*((DWORD *) tmp) += (DWORD) (SvUV( ST(4) ) / 1000);
			}
			else {
				*((DWORD *) tmp) = (DWORD) SvUV( value );
			}
			val = tmp;
			len = sizeof( DWORD );
#else
			if( items > 4 ) {
				((struct timeval *) tmp)->tv_sec = (long) SvIV( value );
				((struct timeval *) tmp)->tv_usec = (long) SvIV( ST(4) );
			}
			else {
				r = SvIV( value );
				((struct timeval *) tmp)->tv_sec = (long) (r / 1000);
				((struct timeval *) tmp)->tv_usec = (long) (r * 1000) % 1000000;
			}
			val = tmp;
			len = sizeof( struct timeval );
#endif
			break;
		default:
			goto _chk;
		}
		goto _set;
	}
_chk:
	if( SvIOK( value ) ) {
		r = (int) SvIV( value );
		val = (void *) &r;
		len = sizeof( int );
	}
	else {
		val = SvPVbyte( value, len );
	}
_set:
	if( mod_sc_setsockopt( sc, level, optname, val, (socklen_t) len ) != SC_OK )
		XSRETURN_EMPTY;
	XSRETURN_YES;


#/*****************************************************************************
# * get_option( this, level, optname )
# *****************************************************************************/

void
get_option( this, level, optname )
	SV *this;
	int level;
	int optname;
PREINIT:
	socket_class_t *sc;
	char tmp[20];
	socklen_t l = sizeof( tmp );
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	l = sizeof( tmp );
	if( mod_sc_getsockopt( sc, level, optname, tmp, &l ) != SC_OK )
		XSRETURN_EMPTY;
	if( level == SOL_SOCKET ) {
		switch( optname ) {
		case SO_LINGER:
			XPUSHs( sv_2mortal(
				newSVuv( ((struct linger *) tmp)->l_onoff ) ) );
			XPUSHs( sv_2mortal(
				newSVuv( ((struct linger *) tmp)->l_linger ) ) );
			break;
		case SO_RCVTIMEO:
		case SO_SNDTIMEO:
#ifdef _WIN32
#ifdef SC_DEBUG
			_debug( "optlen %d\n", l );
#endif
			if( GIMME_V == G_ARRAY ) {
				XPUSHs( sv_2mortal(
					newSVuv( *((DWORD *) tmp) / 1000 ) ) );
				XPUSHs( sv_2mortal(
					newSVuv( (*((DWORD *) tmp) * 1000) % 1000000 ) ) );
			}
			else {
				XPUSHs( sv_2mortal( newSVuv( *((DWORD *) tmp) ) ) );
			}
#else
			if( GIMME_V == G_ARRAY ) {
				XPUSHs( sv_2mortal(
					newSViv( ((struct timeval *) tmp)->tv_sec ) ) );
				XPUSHs( sv_2mortal(
					newSViv( ((struct timeval *) tmp)->tv_usec ) ) );
			}
			else {
				XPUSHs( sv_2mortal( newSVuv(
					((struct timeval *) tmp)->tv_sec * 1000 +
					((struct timeval *) tmp)->tv_usec / 1000
				) ) );
			}
#endif
			break;
		default:
			goto _chk;
		}
		goto _set;
	}
_chk:
#ifdef _WIN32
	if( l == sizeof( DWORD ) ) {
		/* just a try */
		XPUSHs( sv_2mortal( newSVuv( *((DWORD *) tmp) ) ) );
#else
	if( l == sizeof( int ) ) {
		/* just a try */
		XPUSHs( sv_2mortal( newSViv( *((int *) tmp) ) ) );
#endif
	}
	else {
		XPUSHs( sv_2mortal( newSVpvn( tmp, l ) ) );
	}
_set:
	{}


#/*****************************************************************************
# * set_timeout( this, ms )
# *****************************************************************************/

void
set_timeout( this, ms )
	SV *this;
	double ms;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	sc->timeout.tv_sec = (long) (ms / 1000);
	sc->timeout.tv_usec = (long) (ms * 1000) % 1000000;
	XSRETURN_YES;


#/*****************************************************************************
# * get_timeout( this )
# *****************************************************************************/

void
get_timeout( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	XSRETURN_NV( sc->timeout.tv_sec * 1000 + sc->timeout.tv_usec / 1000 );


#/*****************************************************************************
# * is_readable( this [, timeout] )
# *****************************************************************************/

void
is_readable( this, timeout = NULL )
	SV *this;
	SV *timeout;
PREINIT:
	socket_class_t *sc;
	double ms;
	int readable;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	ms = timeout != NULL ? SvNV( timeout ) : -1;
	if( mod_sc_is_readable( sc, ms, &readable ) != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = readable ? &PL_sv_yes : &PL_sv_no;
	XSRETURN(1);


#/*****************************************************************************
# * is_writable( this [, timeout] )
# *****************************************************************************/

void
is_writable( this, timeout = NULL )
	SV *this;
	SV *timeout;
PREINIT:
	socket_class_t *sc;
	double ms;
	int writable;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	ms = timeout != NULL ? SvNV( timeout ) : -1;
	if( mod_sc_is_writable( sc, ms, &writable ) != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = writable ? &PL_sv_yes : &PL_sv_no;
	XSRETURN(1);


#/*****************************************************************************
# * select( this [, read [, write [, error [, timeout]]]] )
# *****************************************************************************/

void
select( this, read = NULL, write = NULL, except = NULL, timeout = NULL )
	SV *this;
	SV *read;
	SV *write;
	SV *except;
	SV *timeout;
PREINIT:
	socket_class_t *sc;
	int dr, dw, de, vr, vw, ve;
	double ms;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	vr = dr = read != NULL && SvTRUE( read );
	vw = dw = write != NULL && SvTRUE( write );
	ve = de = except != NULL && SvTRUE( except );
	ms = timeout != NULL ? SvNV( timeout ) : -1;
	if( mod_sc_select( sc, &vr, &vw, &ve, ms ) != SC_OK )
		XSRETURN_EMPTY;
	if( dr && ! SvREADONLY( read ) )
		sv_setiv( read, vr );
	if( dw && ! SvREADONLY( write ) )
		sv_setiv( write, vw );
	if( de && ! SvREADONLY( except ) )
		sv_setiv( except, ve );
	XSRETURN_IV( vr + vw + ve );


#/*****************************************************************************
# * wait( this, timeout )
# *****************************************************************************/

void
wait( this, timeout )
	SV *this;
	double timeout;
PPCODE:
	if( this != NULL ) {} /* avoid compiler warning */
	mod_sc_sleep( timeout );


#/*****************************************************************************
# * handle( this )
# *****************************************************************************/

void
handle( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSViv( sc->sock ) );
	XSRETURN( 1 );


#/*****************************************************************************
# * state( this )
# *****************************************************************************/

void
state( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSViv( sc->state ) );
	XSRETURN( 1 );


#/*****************************************************************************
# * local_addr( this )
# *****************************************************************************/

void
local_addr( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	char host[NI_MAXHOST], serv[NI_MAXSERV];
	int r, host_len = NI_MAXHOST, serv_len = NI_MAXSERV;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	r = mod_sc_unpack_addr( sc, &sc->l_addr, host, &host_len, serv, &serv_len );
	if( r != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( host, host_len ) );
	XSRETURN(1);


#/*****************************************************************************
# * local_path( this )
# *****************************************************************************/

void
local_path( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	char *s1;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	switch( sc->s_domain ) {
	case AF_UNIX:
		s1 = ((struct sockaddr_un *) sc->l_addr.a )->sun_path;
		ST(0) = sv_2mortal( newSVpvn( s1, strlen( s1 ) ) );
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	XSRETURN(1);


#/*****************************************************************************
# * local_port( this )
# *****************************************************************************/

void
local_port( this )
	SV *this;
PREINIT:
PREINIT:
	socket_class_t *sc;
	char host[NI_MAXHOST], serv[NI_MAXSERV];
	int r, host_len = NI_MAXHOST, serv_len = NI_MAXSERV;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	r = mod_sc_unpack_addr( sc, &sc->l_addr, host, &host_len, serv, &serv_len );
	if( r != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( serv, serv_len ) );
	XSRETURN(1);


#/*****************************************************************************
# * remote_addr( this )
# *****************************************************************************/

void
remote_addr( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	char host[NI_MAXHOST], serv[NI_MAXSERV];
	int r, host_len = NI_MAXHOST, serv_len = NI_MAXSERV;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	r = mod_sc_unpack_addr( sc, &sc->r_addr, host, &host_len, serv, &serv_len );
	if( r != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( host, host_len ) );
	XSRETURN(1);


#/*****************************************************************************
# * remote_path( this )
# *****************************************************************************/

void
remote_path( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	char *s1;
PPCODE:
	if( (sc = socket_class_find( this )) == NULL )
		XSRETURN_EMPTY;
	switch( sc->s_domain ) {
	case AF_UNIX:
		s1 = ((struct sockaddr_un *) sc->r_addr.a )->sun_path;
		ST(0) = sv_2mortal( newSVpvn( s1, strlen( s1 ) ) );
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	XSRETURN(1);


#/*****************************************************************************
# * remote_port( this )
# *****************************************************************************/

void
remote_port( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	char host[NI_MAXHOST], serv[NI_MAXSERV];
	int r, host_len = NI_MAXHOST, serv_len = NI_MAXSERV;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	r = mod_sc_unpack_addr( sc, &sc->r_addr, host, &host_len, serv, &serv_len );
	if( r != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( serv, serv_len ) );
	XSRETURN(1);


#/*****************************************************************************
# * to_string( this )
# *****************************************************************************/

void
to_string( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
	char tmp[1024];
	size_t len = sizeof(tmp);
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	if( mod_sc_to_string( sc, tmp, &len ) != SC_OK )
		XSRETURN_EMPTY;
	ST(0) = sv_2mortal( newSVpvn( tmp, len ) );
	XSRETURN(1);


#/*****************************************************************************
# * is_error( this )
# *****************************************************************************/

void
is_error( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
PPCODE:
	if( (sc = mod_sc_get_socket( this )) == NULL )
		XSRETURN_EMPTY;
	ST(0) = (sc->state == SC_STATE_ERROR) ? &PL_sv_yes : &PL_sv_no;
	XSRETURN(1);


#/*****************************************************************************
# * errno( this )
# *****************************************************************************/

void
errno( this )
	SV *this;
PREINIT:
	socket_class_t *sc;
PPCODE:
	sc = mod_sc_get_socket( this );
	XSRETURN_IV( mod_sc_get_errno( sc ) );


#/*****************************************************************************
# * error( this [, code] )
# *****************************************************************************/

void
error( this, code = 0 )
	SV *this;
	int code;
PREINIT:
	socket_class_t *sc;
	const char *msg;
PPCODE:
	sc = mod_sc_get_socket( this );
	if( code != 0 )
		mod_sc_set_errno( sc, code );
	msg = mod_sc_get_error( sc );
	ST(0) = sv_2mortal( newSVpvn( msg, strlen( msg ) ) );
	XSRETURN(1);



( run in 0.689 second using v1.01-cache-2.11-cpan-5511b514fd6 )