/*
 * This file was generated automatically by xsubpp version 1.9508 from the
 * contents of Class.xs. Do not edit this file, edit Class.xs instead.
 *
 *	ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

#line 1 "Class.xs"
#include "socket_class.h"

#line 13 "Class.c"

XS(XS_Socket__Class_END); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_END)
{
    dXSARGS;
    if (items != 0)
	Perl_croak(aTHX_ "Usage: Socket::Class::END()");
    {
#line 40 "Class.xs"
	my_thread_var_t *tv1, *tv2;
	u_long cascade;
#line 25 "Class.c"
#line 43 "Class.xs"
	if( global.destroyed )
		return;
	global.destroyed = 1;
	_debug( "END called\n" );
	GLOBAL_LOCK();
	for( cascade = 0; cascade < SC_TV_CASCADE; cascade ++ ) {
		tv1 = global.first_thread[cascade];
		while( tv1 != NULL ) {
			tv2 = tv1->next;
			_debug( "freeing tv 0x%08x\n", tv1 );
			my_thread_var_free( tv1 );
			tv1 = tv2;
		}
		global.first_thread[cascade] = global.last_thread[cascade] = NULL;
	}
	GLOBAL_UNLOCK();
#ifdef SC_THREADS
	MUTEX_DESTROY( &global.thread_lock );
#endif
#ifdef _WIN32
	WSACleanup();
#endif
#line 49 "Class.c"
    }
    XSRETURN_EMPTY;
}

#ifdef USE_ITHREADS
#define XSubPPtmpAAAA 1


XS(XS_Socket__Class_CLONE_SKIP); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_CLONE_SKIP)
{
    dXSARGS;
   PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
#line 76 "Class.xs"
	_debug( "CLONE_SKIP called\n" );
	XSRETURN_NO;
#line 68 "Class.c"
	PUTBACK;
	return;
    }
}

#endif

XS(XS_Socket__Class_DESTROY); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_DESTROY)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::DESTROY(this)");
    {
	SV *	this = ST(0);
#line 90 "Class.xs"
#ifndef SC_THREADS
	my_thread_var_t *tv;
#endif
#line 88 "Class.c"
#line 94 "Class.xs"
	_debug( "DESTROY called for tv 0x%08x\n", SvIV( SvRV( this ) ) );
#ifndef SC_THREADS
	tv = my_thread_var_find( this );
	if( tv != NULL ) {
		my_thread_var_rem( tv );
	}
#endif
#line 97 "Class.c"
    }
    XSRETURN_EMPTY;
}


XS(XS_Socket__Class_new); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_new)
{
    dXSARGS;
    if (items < 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::new(class, ...)");
    SP -= items;
    {
	SV *	class = ST(0);
#line 111 "Class.xs"
	my_thread_var_t *tv;
	SV *sv;
	HV *hv;
	int i, ln = 0, bc = 0, bl = 1, rua = 0;
	STRLEN lkey, lval;
	char *key, *val;
	char *la = NULL, *ra = NULL, *lp = NULL, *rp = NULL;
	double tmo = -1;
	fd_set fds;
	socklen_t sl;
#line 123 "Class.c"
#line 122 "Class.xs"
	Newxz( tv, 1, my_thread_var_t );
	tv->s_domain = AF_INET;
	tv->s_type = SOCK_STREAM;
	tv->s_proto = IPPROTO_TCP;
	tv->timeout.tv_sec = 15;
	/* read options */
	for( i = 1; i < items - 1; i += 2 ) {
		if( ! SvPOK( ST(i) ) ) continue;
		key = SvPVx( ST(i), lkey );
		if( strcmp( key, "domain" ) == 0 ) {
			if( SvIOK( ST(i + 1) ) ) {
				tv->s_domain = (int) SvIV( ST(i + 1) );
			}
			else {
				val = SvPVx( ST(i + 1), lval );
				tv->s_domain = Socket_domainbyname( val );
			}
			if( tv->s_domain == AF_UNIX ) {
				tv->s_proto = 0;
			}
			else if( tv->s_domain == AF_BLUETOOTH ) {
				tv->s_proto = BTPROTO_RFCOMM;
			}
		}
		else if( strcmp( key, "type" ) == 0 ) {
			if( SvIOK( ST(i + 1) ) ) {
				tv->s_type = (int) SvIV( ST(i + 1) );
			}
			else {
				val = SvPVx( ST(i + 1), lval );
				tv->s_type = Socket_typebyname( val );
			}
		}
		else if( strcmp( key, "proto" ) == 0 ) {
			if( SvIOK( ST(i + 1) ) ) {
				tv->s_proto = (int) SvIV( ST(i + 1) );
			}
			else {
				val = SvPVx( ST(i + 1), lval );
				tv->s_proto = Socket_protobyname( val );
			}
			if( tv->s_proto == IPPROTO_UDP ) {
				tv->s_type = SOCK_DGRAM;
			}
		}
		else if( strcmp( key, "local_addr" ) == 0 ) {
			la = SvPV( ST(i + 1), lval );
		}
		else if( strcmp( key, "local_path" ) == 0 ) {
			la = SvPV( ST(i + 1), lval );
			tv->s_domain = AF_UNIX;
			tv->s_proto = 0;
		}
		else if( strcmp( key, "local_port" ) == 0 ) {
			lp = SvPV( ST(i + 1), lval );
		}
		else if( strcmp( key, "remote_addr" ) == 0 ) {
			ra = SvPV( ST(i + 1), lval );
		}
		else if( strcmp( key, "remote_path" ) == 0 ) {
			ra = SvPV( ST(i + 1), lval );
			tv->s_domain = AF_UNIX;
			tv->s_proto = 0;
		}
		else if( strcmp( key, "remote_port" ) == 0 ) {
			rp = SvPV( ST(i + 1), lval );
		}
		else if( strcmp( key, "listen" ) == 0 ) {
			ln = (int) SvIV( ST(i + 1) );
		}
		else if( strcmp( key, "blocking" ) == 0 ) {
			bl = (int) SvIV( ST(i + 1) );
		}
		else if( strcmp( key, "broadcast" ) == 0 ) {
			bc = (int) SvIV( ST(i + 1) );
		}
		else if( strcmp( key, "reuseaddr" ) == 0 ) {
			rua = (int) SvIV( ST(i + 1) );
		}
		else if( strcmp( key, "timeout" ) == 0 ) {
			tmo = SvNV( ST(i + 1) );
		}
	}
	/* create the socket */
	tv->sock = socket( tv->s_domain, tv->s_type, tv->s_proto );
	if( tv->sock == INVALID_SOCKET ) {
		_debug( "socket(%d,%d,%d) create error %d\n",
			tv->s_domain, tv->s_type, tv->s_proto, tv->sock );
		goto error;
	}
	/* set socket options */
	if( bc &&
		setsockopt(
			tv->sock, SOL_SOCKET, SO_BROADCAST, (void *) &bc, sizeof( int )
		) == SOCKET_ERROR
	) goto error;
	if( rua &&
		setsockopt(
			tv->sock, SOL_SOCKET, SO_REUSEADDR, (void *) &rua, sizeof( int )
		) == SOCKET_ERROR
	) goto error;
	/* set timeout */
	if( tmo >= 0 ) {
		tv->timeout.tv_sec = (long) (tmo / 1000.0);
		tv->timeout.tv_usec = (long) (tv->timeout.tv_sec * 1000 - tmo) * 1000;
	}
	/* bind and listen */
	if( la != NULL || lp != NULL || ln != 0 ) {
		switch( tv->s_domain ) {
		case AF_INET:
		case AF_INET6:
		default:
			i = Socket_setaddr_INET( tv, la, lp, ADDRUSE_LISTEN );
			if( i != 0 ) {
				global.last_errno = i;
				goto error2;
			}
			break;
		case AF_UNIX:
			remove( la );
			Socket_setaddr_UNIX( &tv->l_addr, la );
			break;
		}

		_debug( "bind socket %d\n", tv->sock );
		if( bind(
				tv->sock, (struct sockaddr *) tv->l_addr.a, tv->l_addr.l
			) == SOCKET_ERROR
		) goto error;
		tv->state = SOCK_STATE_BOUND;
		tv->l_addr.l = SOCKADDR_SIZE_MAX;
		getsockname( tv->sock, (struct sockaddr *) tv->l_addr.a, &tv->l_addr.l );
		if( ln != 0 ) {
			_debug( "listen on %s %s\n", la, lp );
			if( listen( tv->sock, ln ) == SOCKET_ERROR )
				goto error;
			tv->state = SOCK_STATE_LISTEN;
		}
	}
	/* connect */
	if( ra != NULL || rp != NULL ) {
		switch( tv->s_domain ) {
		case AF_INET:
		case AF_INET6:
		default:
			i = Socket_setaddr_INET( tv, ra, rp, ADDRUSE_CONNECT );
			if( i != 0 ) {
				global.last_errno = i;
				goto error2;
			}
			break;
		case AF_UNIX:
			Socket_setaddr_UNIX( &tv->r_addr, ra );
			break;
		}
		if( Socket_setblocking( tv->sock, 0 ) == SOCKET_ERROR )
			goto error;
		_debug( "connect to %s %s\n", ra, rp );
		if( connect(
				tv->sock, (struct sockaddr *) tv->r_addr.a, tv->r_addr.l
			) == SOCKET_ERROR
		) {
			i = Socket_errno();
			if( i == EINPROGRESS || i == EWOULDBLOCK ) {
				FD_ZERO( &fds ); 
				FD_SET( tv->sock, &fds );
				if( select(
						(int) (tv->sock + 1), NULL, &fds, NULL, &tv->timeout
					) > 0
				) {
					sl = sizeof( int );
					if( getsockopt(
							tv->sock, SOL_SOCKET, SO_ERROR, (void *) (&i), &sl
						) == SOCKET_ERROR
					) {
						goto error;
					}
					if( i ) {
						_debug( "getsockopt SO_ERROR %d\n", i );
						global.last_errno = i;
						goto error2;
					}
				}
				else {
					_debug( "connect timed out %u\n", ETIMEDOUT );
					global.last_errno = ETIMEDOUT;
					goto error2;
				}	
			}
			else {
				_debug( "connect failed %d\n", i );
				global.last_errno = i;
				goto error2;
			}
		}
		if( bl ) {
			if( Socket_setblocking( tv->sock, 1 ) == SOCKET_ERROR )
				goto error;
		}
		else
			tv->non_blocking = 1;
		tv->l_addr.l = SOCKADDR_SIZE_MAX;
		getsockname( tv->sock, (struct sockaddr *) tv->l_addr.a, &tv->l_addr.l );
		tv->state = SOCK_STATE_CONNECTED;
	}
	if( ! bl && ! tv->non_blocking ) {
		if( Socket_setblocking( tv->sock, 0 ) == SOCKET_ERROR )
			goto error;
		tv->non_blocking = 1;
	}
	/* create the class */
	sv = sv_2mortal( newSViv( PTR2IV( tv ) ) );
	key = SvPV( class, lkey );
	Newx( tv->classname, lkey + 1, char );
	Copy( key, tv->classname, lkey + 1, char );
	_debug( "bless socket %d to %s\n", tv->sock, key );
	hv = gv_stashpv( key, 0 );
	ST(0) = sv_bless( sv_2mortal( newRV( sv ) ), hv );
	my_thread_var_add( tv );
	global.last_errno = 0;
	XSRETURN( 1 );
error:
	global.last_errno = Socket_errno();
error2:
	XSRETURN_EMPTY;
#line 350 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_connect); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_connect)
{
    dXSARGS;
    if (items < 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::connect(this, ...)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 357 "Class.xs"
	my_thread_var_t *tv;
	STRLEN l1, l2;
	const char *s1, *s2;
	fd_set fds;
	int r;
	socklen_t sl;
	double ms;
#line 374 "Class.c"
#line 365 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	tv->last_error[0] = '\0';
	switch( tv->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) );
				tv->timeout.tv_sec = (long) (ms / 1000);
				tv->timeout.tv_usec = (long) (ms * 1000) % 1000000;
			}
		case 3:
			s1 = SvPV( ST(1), l1 );
			s2 = SvPV( ST(2), l2 );
			tv->last_errno =
				Socket_setaddr_INET( tv, s1, s2, ADDRUSE_CONNECT );
			if( tv->last_errno != 0 )
				goto error;
			break;
		case 2:
			s1 = SvPV( ST(1), l1 );
			tv->last_errno =
				Socket_setaddr_INET( tv, s1, NULL, ADDRUSE_CONNECT );
			if( tv->last_errno != 0 )
				goto error;
			break;
		case 1:
			if( tv->state != SOCK_STATE_CLOSED ) {
				tv->last_errno =
					Socket_setaddr_INET( tv, NULL, NULL, ADDRUSE_CONNECT );
				if( tv->last_errno != 0 )
					goto error;
			}
			break;
		}
		break;
	case AF_UNIX:
		switch( items ) {
		case 3:
		default:
			if( SvNOK( ST(2) ) || SvIOK( ST(2) ) ) {
				ms = SvNV( ST(2) );
				tv->timeout.tv_sec = (long) (ms / 1000);
				tv->timeout.tv_usec = (long) (ms * 1000) % 1000000;
			}
		case 2:
			s1 = SvPV( ST(1), l1 );
			Socket_setaddr_UNIX( &tv->r_addr, s1 );
			break;
		case 1:
			if( tv->state != SOCK_STATE_CLOSED ) {
				Socket_setaddr_UNIX( &tv->r_addr, NULL );
			}
			break;
		}
		break;
	}
	if( tv->state == SOCK_STATE_CONNECTED ) {
		Socket_close( tv->sock );
		tv->state = SOCK_STATE_CLOSED;
	}
	if( tv->sock == INVALID_SOCKET ) {
		tv->sock = socket( tv->s_domain, tv->s_type, tv->s_proto );
		if( tv->sock == INVALID_SOCKET ) {
			tv->last_errno = Socket_errno();
			goto error;
		}
	}
	_debug( "connecting socket %d state %d addrlen %d\n",
		tv->sock, tv->state, tv->r_addr.l );
	if( ! tv->non_blocking ) {
		if( Socket_setblocking( tv->sock, 0 ) == SOCKET_ERROR ) {
			tv->last_errno = Socket_errno();
			goto error;
		}
	}
	if( connect( tv->sock, (struct sockaddr *) tv->r_addr.a, tv->r_addr.l )
		== SOCKET_ERROR
	) {
		r = Socket_errno();
		if( r == EINPROGRESS || r == EWOULDBLOCK ) {
			FD_ZERO( &fds ); 
			FD_SET( tv->sock, &fds );
			if( select(
					(int) (tv->sock + 1), NULL, &fds, NULL, &tv->timeout
				) > 0
			) {
				sl = sizeof( int );
				if( getsockopt(
						tv->sock, SOL_SOCKET, SO_ERROR, (void*) (&r), &sl
					) == SOCKET_ERROR
				) {
					tv->last_errno = Socket_errno();
					goto error;
				}
				if( r ) {
					_debug( "getsockopt SO_ERROR %d\n", r );
					tv->last_errno = r;
					goto error;
				}
			}
			else {
				_debug( "connect timed out %u\n", ETIMEDOUT );
				tv->last_errno = ETIMEDOUT;
				goto error;
			}	
		}
		else {
			_debug( "connect failed %d\n", r );
			tv->last_errno = r;
			goto error;
		}
	}
	if( ! tv->non_blocking ) {
		if( Socket_setblocking( tv->sock, 1 ) == SOCKET_ERROR ) {
			tv->last_errno = Socket_errno();
			goto error;
		}
	}
	tv->l_addr.l = SOCKADDR_SIZE_MAX;
	getsockname( tv->sock, (struct sockaddr *) tv->l_addr.a, &tv->l_addr.l );
	tv->state = SOCK_STATE_CONNECTED;
	tv->last_errno = 0;
	TV_UNLOCK( tv );
	XSRETURN_YES;
error:
	TV_UNLOCK( tv );
	XSRETURN_EMPTY;
#line 509 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_free); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_free)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::free(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 508 "Class.xs"
	my_thread_var_t *tv;
#line 527 "Class.c"
#line 510 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	//shutdown( tv->sock, 2 );
	my_thread_var_rem( tv );
	XSRETURN_YES;
#line 534 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_close); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_close)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::close(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 525 "Class.xs"
	my_thread_var_t *tv;
#line 552 "Class.c"
#line 527 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	_debug( "closing socket %d tv %u\n", tv->sock, tv );
	Socket_close( tv->sock );
	if( tv->s_domain == AF_UNIX ) {
		remove( ((struct sockaddr_un *) tv->l_addr.a)->sun_path );
	}
	tv->state = SOCK_STATE_CLOSED;
	memset( &tv->l_addr, 0, sizeof( tv->l_addr ) );
	memset( &tv->r_addr, 0, sizeof( tv->r_addr ) );
	TV_UNLOCK( tv );
	XSRETURN_YES;
#line 567 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_shutdown); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_shutdown)
{
    dXSARGS;
    if (items < 1 || items > 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::shutdown(this, how = 0)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	how;
#line 551 "Class.xs"
	my_thread_var_t *tv;
	int r;
#line 587 "Class.c"

	if (items < 2)
	    how = 0;
	else {
	    how = (int)SvIV(ST(1));
	}
#line 554 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	r = shutdown( tv->sock, how );
	if( r == SOCKET_ERROR ) {
		tv->last_errno = Socket_errno();
		tv->state = SOCK_STATE_ERROR;
		TV_UNLOCK( tv );
		XSRETURN_EMPTY;
	}
	else {
		tv->last_errno = 0;
		TV_UNLOCK( tv );
		XSRETURN_YES;
	}
#line 610 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_bind); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_bind)
{
    dXSARGS;
    if (items < 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::bind(this, ...)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 579 "Class.xs"
	my_thread_var_t *tv;
	STRLEN l1;
	const char *s1, *s2;
#line 630 "Class.c"
#line 583 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	tv->last_error[0] = '\0';
	switch( tv->s_domain ) {
	case AF_INET:
	case AF_INET6:
	default:
		switch( items ) {
		case 3:
			s1 = SvPV( ST(1), l1 );
			s2 = SvPV( ST(2), l1 );
			tv->last_errno = Socket_setaddr_INET( tv, s1, s2, ADDRUSE_LISTEN );
			if( tv->last_errno != 0 )
				goto error;
			break;
		case 2:
			s1 = SvPV( ST(1), l1 );
			tv->last_errno = Socket_setaddr_INET( tv, s1, NULL, ADDRUSE_LISTEN );
			if( tv->last_errno != 0 )
				goto error;
			break;
		case 1:
			if( tv->state != SOCK_STATE_CLOSED ) {
				tv->last_errno = Socket_setaddr_INET( tv, NULL, NULL, ADDRUSE_LISTEN );
				if( tv->last_errno != 0 )
					goto error;
			}
			break;
		}
		break;
	case AF_UNIX:
		switch( items ) {
		case 2:
			s1 = SvPV( ST(1), l1 );
			Socket_setaddr_UNIX( &tv->l_addr, s1 );
			break;
		case 1:
			if( tv->state != SOCK_STATE_CLOSED ) {
				Socket_setaddr_UNIX( &tv->l_addr, NULL );
			}
			break;
		}
		remove( ((struct sockaddr_un *) tv->l_addr.a)->sun_path );
		break;
	}
	if( tv->sock == INVALID_SOCKET ) {
		tv->sock = socket( tv->s_domain, tv->s_type, tv->s_proto );
		if( tv->sock == INVALID_SOCKET ) {
			tv->last_errno = Socket_errno();
			goto error;
		}
	}
	if( bind( tv->sock, (struct sockaddr *) tv->l_addr.a, tv->l_addr.l )
		== SOCKET_ERROR
	) {
		tv->last_errno = Socket_errno();
		goto error;
	}
	getsockname( tv->sock, (struct sockaddr *) tv->l_addr.a, &tv->l_addr.l );
	tv->state = SOCK_STATE_BOUND;
	tv->last_errno = 0;
	TV_UNLOCK( tv );
	XSRETURN_YES;
error:
	TV_UNLOCK( tv );
	XSRETURN_EMPTY;
#line 699 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_listen); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_listen)
{
    dXSARGS;
    if (items < 1 || items > 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::listen(this, queue = SOMAXCONN)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	queue;
#line 661 "Class.xs"
	my_thread_var_t *tv;
#line 718 "Class.c"

	if (items < 2)
	    queue = SOMAXCONN;
	else {
	    queue = (int)SvIV(ST(1));
	}
#line 663 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	if( listen( tv->sock, queue ) == SOCKET_ERROR ) {
		TV_ERRNOLAST( tv );
		TV_UNLOCK( tv );
		XSRETURN_EMPTY;
	}
	TV_ERRNO( tv, 0 );
	tv->state = SOCK_STATE_LISTEN;
	TV_UNLOCK( tv );
	XSRETURN_YES;
#line 738 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_accept); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_accept)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::accept(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 685 "Class.xs"
	my_thread_var_t *tv, *tv2;
	SOCKET s;
	my_sockaddr_t addr;
	SV *sv;
	HV *hv;
#line 760 "Class.c"
#line 691 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	addr.l = SOCKADDR_SIZE_MAX;
	s = accept( tv->sock, (struct sockaddr *) addr.a, &addr.l );
	if( s == INVALID_SOCKET ) {			
		TV_ERRNOLAST( tv );
		switch( tv->last_errno ) {
		case EWOULDBLOCK:
			// threat not as an error
			tv->last_errno = 0;
			TV_UNLOCK( tv );
			XSRETURN_NO;
		default:
			_debug( "accept error %u\n", tv->last_errno );
			tv->state = SOCK_STATE_ERROR;
			TV_UNLOCK( tv );
			XSRETURN_EMPTY;
		}
	}
	Newxz( tv2, 1, my_thread_var_t );
	_debug( "accepting socket %d tv 0x%08x %u:%u\n", s, tv2, tv->l_addr.l, addr.l );
	tv2->s_domain = tv->s_domain;
	tv2->s_type = tv->s_type;
	tv2->s_proto = tv->s_proto;
	tv2->sock = s;
	tv2->state = SOCK_STATE_CONNECTED;
	Copy( &addr, &tv2->r_addr, MYSASIZE( addr ), BYTE );
	tv2->l_addr.l = SOCKADDR_SIZE_MAX;
	getsockname( s, (struct sockaddr *) tv2->l_addr.a, &tv2->l_addr.l );
	sv = sv_2mortal( newSViv( PTR2IV( tv2 ) ) );
	hv = gv_stashpv( tv->classname, 0 );
	ST(0) = sv_bless( newRV( sv ), hv );
	my_thread_var_add( tv2 );
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 798 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_recv); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_recv)
{
    dXSARGS;
    if (items < 3 || items > 4)
	Perl_croak(aTHX_ "Usage: Socket::Class::recv(this, buf, len, flags = 0)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	buf = ST(1);
	size_t	len = (size_t)SvUV(ST(2));
	unsigned long	flags;
#line 740 "Class.xs"
	my_thread_var_t *tv;
	int r;
#line 820 "Class.c"

	if (items < 4)
	    flags = 0;
	else {
	    flags = (unsigned long)SvUV(ST(3));
	}
#line 743 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	if( tv->rcvbuf_len < len ) {
		tv->rcvbuf_len = len;
		Renew( tv->rcvbuf, len, char );
	}
	r = recv( tv->sock, tv->rcvbuf, (int) len, flags );
	if( r == SOCKET_ERROR ) {
		TV_ERRNOLAST( tv );
		switch( tv->last_errno ) {
		case EWOULDBLOCK:
			// threat not as an error
			tv->last_errno = 0;
			TV_UNLOCK( tv );
			XSRETURN_NO;
		default:
			_debug( "recv error %u\n", tv->last_errno );
			tv->state = SOCK_STATE_ERROR;
			TV_UNLOCK( tv );
			XSRETURN_EMPTY;
		}
		sv_setpvn( buf, "", 0 );
	}
	else if( r != 0 ) {
		tv->last_errno = 0;
		sv_setpvn( buf, tv->rcvbuf, r );
		TV_UNLOCK( tv );
		XSRETURN_IV( r );
	}
	tv->last_errno = ECONNRESET;
	tv->state = SOCK_STATE_ERROR;
	TV_UNLOCK( tv );
	XSRETURN_EMPTY;
#line 862 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_send); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_send)
{
    dXSARGS;
    if (items < 2 || items > 3)
	Perl_croak(aTHX_ "Usage: Socket::Class::send(this, buf, flags = 0)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	buf = ST(1);
	unsigned long	flags;
#line 789 "Class.xs"
	my_thread_var_t *tv;
	const char *msg;
	STRLEN len;
	int r;
#line 885 "Class.c"

	if (items < 3)
	    flags = 0;
	else {
	    flags = (unsigned long)SvUV(ST(2));
	}
#line 794 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	msg = SvPV( buf, len );
	r = send( tv->sock, msg, (int) len, flags );
	if( r == SOCKET_ERROR ) {
		TV_ERRNOLAST( tv );
		switch( tv->last_errno ) {
		case EWOULDBLOCK:
			// threat not as an error
			tv->last_errno = 0;
			TV_UNLOCK( tv );
			XSRETURN_NO;
		default:
			_debug( "send error %u\n", tv->last_errno );
			tv->state = SOCK_STATE_ERROR;
			TV_UNLOCK( tv );
			XSRETURN_EMPTY;
		}
	}
	else if( r != 0 ) {
		tv->last_errno = 0;
		TV_UNLOCK( tv );
		XSRETURN_IV( r );
	}
	tv->last_errno = ECONNRESET;
	_debug( "send error %u\n", tv->last_errno );
	tv->state = SOCK_STATE_ERROR;
	TV_UNLOCK( tv );
	XSRETURN_EMPTY;
#line 923 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_recvfrom); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_recvfrom)
{
    dXSARGS;
    if (items < 3 || items > 4)
	Perl_croak(aTHX_ "Usage: Socket::Class::recvfrom(this, buf, len, flags = 0)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	buf = ST(1);
	size_t	len = (size_t)SvUV(ST(2));
	unsigned long	flags;
#line 837 "Class.xs"
	my_thread_var_t *tv;
	int r;
	my_sockaddr_t peer;
#line 946 "Class.c"

	if (items < 4)
	    flags = 0;
	else {
	    flags = (unsigned long)SvUV(ST(3));
	}
#line 841 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	if( tv->rcvbuf_len < len ) {
		tv->rcvbuf_len = len;
		Renew( tv->rcvbuf, len, char );
	}
	peer.l = SOCKADDR_SIZE_MAX;
	r = recvfrom(
		tv->sock, tv->rcvbuf, (int) len, flags,
		(struct sockaddr *) peer.a, &peer.l
	);
	if( r == SOCKET_ERROR ) {
		TV_ERRNOLAST( tv );
		sv_setpvn( buf, "", 0 );
		switch( tv->last_errno ) {
		case EWOULDBLOCK:
			// threat not as an error
			tv->last_errno = 0;
			TV_UNLOCK( tv );
			XSRETURN_NO;
		default:
			_debug( "recvfrom error %u\n", tv->last_errno );
			tv->state = SOCK_STATE_ERROR;
			TV_UNLOCK( tv );
			XSRETURN_EMPTY;
		}
	}
	else if( r != 0 ) {
		tv->last_errno = 0;
		sv_setpvn( buf, tv->rcvbuf, r );
		// remember who we received from
		Copy( &peer, &tv->r_addr, peer.l + sizeof( int ), BYTE );
		TV_UNLOCK( tv );
		ST(0) = sv_2mortal( newSVpvn( (char *) &peer, MYSASIZE( peer ) ) );
		XSRETURN( 1 );
	}
	tv->last_errno = ECONNRESET;
	tv->state = SOCK_STATE_ERROR;
	TV_UNLOCK( tv );
	XSRETURN_EMPTY;
#line 995 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_sendto); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_sendto)
{
    dXSARGS;
    if (items < 2 || items > 4)
	Perl_croak(aTHX_ "Usage: Socket::Class::sendto(this, buf, to = NULL, flags = 0)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	buf = ST(1);
	SV *	to;
	unsigned long	flags;
#line 895 "Class.xs"
	my_thread_var_t *tv;
	const char *msg;
	STRLEN len;
	my_sockaddr_t *peer;
	int r;
#line 1020 "Class.c"

	if (items < 3)
	    to = NULL;
	else {
	    to = ST(2);
	}

	if (items < 4)
	    flags = 0;
	else {
	    flags = (unsigned long)SvUV(ST(3));
	}
#line 901 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	if( to != NULL && SvPOK( to ) ) {
		peer = (my_sockaddr_t *) SvPVbyte( to, len );
		if( len < sizeof( int ) || len != MYSASIZE(*peer) ) {
			snprintf(
				global.last_error, sizeof( global.last_error ),
				"Invalid address"
			);
		}
		// remember who we send to
		Copy( peer, &tv->r_addr, len, BYTE );
	}
	else {
		peer = &tv->r_addr;
	}
	msg = SvPV( buf, len );
	r = sendto(
		tv->sock, msg, (int) len, flags,
		(struct sockaddr *) peer->a, peer->l
	);
	if( r == SOCKET_ERROR ) {
		TV_ERRNOLAST( tv );
		switch( tv->last_errno ) {
		case EWOULDBLOCK:
			// threat not as an error
			tv->last_errno = 0;
			TV_UNLOCK( tv );
			XSRETURN_NO;
		default:
			_debug( "sendto error %u\n", tv->last_errno );
			tv->state = SOCK_STATE_ERROR;
			TV_UNLOCK( tv );
			XSRETURN_EMPTY;
		}
	}
	else if( r != 0 ) {
		tv->last_errno = 0;
		TV_UNLOCK( tv );
		XSRETURN_IV( r );
	}
	tv->last_errno = ECONNRESET;
	tv->state = SOCK_STATE_ERROR;
	TV_UNLOCK( tv );
	XSRETURN_EMPTY;
#line 1080 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_read); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_read)
{
    dXSARGS;
    if (items != 3)
	Perl_croak(aTHX_ "Usage: Socket::Class::read(this, buf, len)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	buf = ST(1);
	size_t	len = (size_t)SvUV(ST(2));
#line 959 "Class.xs"
	my_thread_var_t *tv;
	int r;
	size_t pos = 0;
#line 1102 "Class.c"
#line 963 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	if( tv->rcvbuf_len < len ) {
		tv->rcvbuf_len = len;
		Renew( tv->rcvbuf, len, char );
	}
	while( len > 0 ) {
		r = recv( tv->sock, &tv->rcvbuf[pos], (int) len, 0 );
		//_debug( "got %d of %d pos %d\n", r, len, pos );
		if( r == SOCKET_ERROR ) {
			if( pos > 0 )
				break;
			sv_setpvn( buf, "", 0 );
			TV_ERRNOLAST( tv );
			switch( tv->last_errno ) {
			case EWOULDBLOCK:
				// threat not as an error
				tv->last_errno = 0;
				TV_UNLOCK( tv );
				XSRETURN_NO;
			default:
				_debug( "read error %u\n", tv->last_errno );
				tv->state = SOCK_STATE_ERROR;
				TV_UNLOCK( tv );
				XSRETURN_EMPTY;
			}
		}
		else if( r == 0 ) {
			if( pos > 0 )
				break;
			tv->last_errno = ECONNRESET;
			_debug( "read error %u\n", tv->last_errno );
			tv->state = SOCK_STATE_ERROR;
			TV_UNLOCK( tv );
			XSRETURN_EMPTY;
		}
		else {
			pos += r;
			len -= r;
		}
	}
	tv->last_errno = 0;
	sv_setpvn( buf, tv->rcvbuf, pos );
	TV_UNLOCK( tv );
	XSRETURN_IV( pos );
#line 1150 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_write); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_write)
{
    dXSARGS;
    if (items < 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::write(this, buf, ...)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	buf = ST(1);
#line 1020 "Class.xs"
	const char *msg;
	STRLEN len, l2;
	int r;
#line 1171 "Class.c"
#line 1024 "Class.xs"
	msg = SvPV( buf, len );
	if( items > 2 ) {
		l2 = SvIV( ST(2) );
		if( l2 < len )
			len = l2;
	}
	r = Socket_write( this, msg, len );
	if( r != SOCKET_ERROR )
		XSRETURN_IV( r );
	else
		XSRETURN_EMPTY;
#line 1184 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_writeline); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_writeline)
{
    dXSARGS;
    if (items != 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::writeline(this, buf)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	buf = ST(1);
#line 1046 "Class.xs"
	const char *msg;
	char *tmp;
	STRLEN len;
	int r;
#line 1206 "Class.c"
#line 1051 "Class.xs"
	msg = SvPVx( buf, len );
	Newx( tmp, len + 2, char );
	Copy( msg, tmp, len, char );
	tmp[len] = '\n';
	r = Socket_write( this, tmp, len + 1 );
	Safefree( tmp );
	if( r != SOCKET_ERROR )
		XSRETURN_IV( r );
	else
		XSRETURN_EMPTY;
#line 1218 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_print); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_print)
{
    dXSARGS;
    if (items < 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::print(this, ...)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 1071 "Class.xs"
	const char *s1;
	char *tmp = NULL;
	STRLEN l1, len = 0, pos = 0;
	int r;
#line 1239 "Class.c"
#line 1076 "Class.xs"
	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 = Socket_write( this, tmp, pos );
		Safefree( tmp );
		if( r != SOCKET_ERROR )
			XSRETURN_IV( r );
		else
			XSRETURN_EMPTY;
	}
#line 1260 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_readline); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_readline)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::readline(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 1105 "Class.xs"
	my_thread_var_t *tv;
	int r;
	size_t i, pos = 0, len = 256;
#line 1280 "Class.c"
#line 1109 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	while( 1 ) {
		if( tv->rcvbuf_len < pos + len ) {
			tv->rcvbuf_len = pos + len + 1;
			Renew( tv->rcvbuf, tv->rcvbuf_len, char );
		}
		r = recv( tv->sock, &tv->rcvbuf[pos], (int) len, MSG_PEEK );
		if( r == SOCKET_ERROR ) {
			if( pos > 0 )
				break;
			tv->last_errno = Socket_errno();
			switch( tv->last_errno ) {
			case EWOULDBLOCK:
				// threat not as an error
				tv->last_errno = 0;
				ST(0) = sv_2mortal( newSVpvn( "", 0 ) );
				break;
			default:
				_debug( "readline error %u\n", tv->last_errno );
				tv->state = SOCK_STATE_ERROR;
				ST(0) = &PL_sv_undef;
				break;
			}
			goto exit;
		}
		else if( r == 0 ) {
			if( pos > 0 )
				break;
			tv->last_errno = ECONNRESET;
			_debug( "readline error %u\n", tv->last_errno );
			tv->state = SOCK_STATE_ERROR;
			ST(0) = &PL_sv_undef;
			goto exit;
		}
		for( i = 0; i < (size_t) r; i ++ ) {
			if( tv->rcvbuf[pos + i] == '\n' ) {
				// found newline
				_debug( "found newline at %d + %d of %d\n", pos, i, r );
				/*
				if( pos + i > 0 && tv->rcvbuf[pos + i - 1] == '\r' ) {
					i --;
				}
				*/
				ST(0) = sv_2mortal( newSVpvn( tv->rcvbuf, pos + i + 1 ) );
				r = recv( tv->sock, &tv->rcvbuf[pos], (int) i, 0 );
				goto exit;
			}
		}
		r = recv( tv->sock, &tv->rcvbuf[pos], (int) i, 0 );
		pos += i;
	}
	ST(0) = sv_2mortal( newSVpvn( tv->rcvbuf, pos ) );
exit:
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 1339 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_pack_addr); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_pack_addr)
{
    dXSARGS;
    if (items < 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::pack_addr(this, addr, ...)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	addr = ST(1);
#line 1177 "Class.xs"
	my_thread_var_t *tv;
#ifndef SC_OLDNET
	struct addrinfo aih;
	struct addrinfo *ail = NULL;
	const char *s2;
	int r;
#else
	struct hostent *he;
#endif
	const char *s1;
	my_sockaddr_t saddr;
	STRLEN len;
	SOCKADDR_L2CAP *l2a;
#line 1370 "Class.c"
#line 1191 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	switch( tv->s_domain ) {
	case AF_UNIX:
		s1 = SvPV( addr, len );
		Socket_setaddr_UNIX( &saddr, s1 );
		ST(0) = sv_2mortal( newSVpvn( (char *) &saddr, MYSASIZE(saddr) ) );
		break;
	case AF_BLUETOOTH:
		if( tv->s_proto == BTPROTO_L2CAP ) {
			saddr.l = sizeof( SOCKADDR_L2CAP );
			l2a = (SOCKADDR_L2CAP *) saddr.a;
			l2a->bt_family = AF_BLUETOOTH;
			my_str2ba( SvPV( addr, len ), &l2a->bt_bdaddr );
			l2a->bt_port = items > 2 ? (uint8_t) SvIV( ST(2) ) : 0;
			ST(0) = sv_2mortal( newSVpvn( (char *) &saddr, MYSASIZE(saddr) ) );
		}
		else
			goto _default;
		break;
#ifndef SC_OLDNET
	case AF_INET:
	case AF_INET6:
	default:
_default:
		memset( &aih, 0, sizeof( struct addrinfo ) );
		aih.ai_family = tv->s_domain;
		aih.ai_socktype = tv->s_type;
		aih.ai_protocol = tv->s_proto;
		s1 = SvPV( addr, len );
		s2 = items > 2 ? SvPV( ST(2), len ) : NULL;
		r = getaddrinfo( s1, s2, &aih, &ail );
		if( r != 0 ) {
			_debug( "getaddrinfo('%s', '%s') failed %d\n", s1, s2, r );
			TV_ERRNO( tv, r );
			ST(0) = &PL_sv_undef;
			goto exit;
		}
		saddr.l = (socklen_t) ail->ai_addrlen;
		memcpy( saddr.a, ail->ai_addr, ail->ai_addrlen );
		freeaddrinfo( ail );
		ST(0) = sv_2mortal( newSVpvn( (char *) &saddr, MYSASIZE(saddr) ) );
		break;
#else
	case AF_INET:
		GLOBAL_LOCK();
		s1 = SvPV( addr, len );
		saddr.l = sizeof( struct sockaddr_in );
		memset( saddr.a, 0, saddr.l );
		((struct sockaddr_in *) saddr.a)->sin_family = AF_INET;
		if( s1[0] >= '0' && s1[0] <= '9' ) {
			((struct sockaddr_in *) saddr.a)->sin_addr.s_addr = inet_addr( s1 );
		}
		else {
			he = gethostbyname( s1 );
			if( he == NULL ) {
				TV_ERRNOLAST( tv );
				ST(0) = &PL_sv_undef;
				goto _inet4e;
			}
			((struct sockaddr_in *) saddr.a)->sin_addr =
				*(struct in_addr*) he->h_addr;
		}
		if( items > 2 ) {
			s1 = SvPV( ST(2), len );
			if( s1[0] >= '0' && s1[0] <= '9' )
				((struct sockaddr_in *) saddr.a)->sin_port
					= htons( atoi( s1 ) );
			else {
				struct servent *se;
				se = getservbyname( s1, NULL );
				if( se == NULL ) {
					TV_ERRNOLAST( tv );
					ST(0) = &PL_sv_undef;
					goto _inet4e;
				}
				((struct sockaddr_in *) saddr.a)->sin_port = se->s_port;
			}
		}
		ST(0) = sv_2mortal( newSVpvn( (char *) &saddr, MYSASIZE(saddr) ) );
_inet4e:
		GLOBAL_UNLOCK();
		break;
	case AF_INET6:
		GLOBAL_LOCK();
		s1 = SvPV( addr, len );
		saddr.l = sizeof( struct sockaddr_in6 );
		memset( saddr.a, 0, saddr.l );
		((struct sockaddr_in6 *) saddr.a)->sin6_family = AF_INET6;
#ifndef _WIN32
		if( ( s1[0] >= '0' && s1[0] <= '9' ) || s1[0] == ':' ) {
			if( inet_pton(
					AF_INET6, s1, &((struct sockaddr_in6 *) saddr.a)->sin6_addr
				) != 0 )
			{
				_debug( "inet_pton failed %d\n", Socket_errno() );
				TV_ERRNOLAST( tv );
				ST(0) = &PL_sv_undef;
				goto _inet6e;
			}
		}
		else {
			he = gethostbyname( s1 );
			if( he == NULL ) {
				TV_ERRNOLAST( tv );
				ST(0) = &PL_sv_undef;
				goto _inet6e;
			}
			if( he->h_addrtype != AF_INET6 ) {
				TV_ERROR( tv, "invalid address family type" );
				ST(0) = &PL_sv_undef;
				goto _inet6e;
			}
			Copy(
				he->h_addr, &((struct sockaddr_in6 *) saddr.a)->sin6_addr,
				he->h_length, char
			);
		}
		if( items > 2 ) {
			s1 = SvPV( ST(2), len );
			if( s1[0] >= '0' && s1[0] <= '9' )
				((struct sockaddr_in6 *) saddr.a)->sin6_port
					= htons( atol( s1 ) );
			else {
				struct servent *se;
				se = getservbyname( s1, NULL );
				if( se == NULL ) {
					TV_ERRNOLAST( tv );
					ST(0) = &PL_sv_undef;
					goto _inet6e;
				}
				((struct sockaddr_in6 *) saddr.a)->sin6_port = se->s_port;
			}
		}
#endif
		ST(0) = sv_2mortal( newSVpvn( (char *) &saddr, MYSASIZE(saddr) ) );
_inet6e:
		GLOBAL_UNLOCK();
		break;
	default:
_default:
		break;
#endif
	}
exit:
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 1520 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_unpack_addr); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_unpack_addr)
{
    dXSARGS;
    if (items != 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::unpack_addr(this, addr)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	addr = ST(1);
#line 1350 "Class.xs"
	my_thread_var_t *tv;
	STRLEN len;
	my_sockaddr_t *saddr;
	SOCKADDR_L2CAP *l2a;
	char tmp[40], *s1;
	int r;
#line 1544 "Class.c"
#line 1357 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	saddr = (my_sockaddr_t *) SvPVbyte( addr, len );
	if( len < sizeof( int ) || len != MYSASIZE(*saddr) ) {
		snprintf(
			tv->last_error, sizeof( tv->last_error ),
			"Invalid address"
		);
	}
	switch( tv->s_domain ) {
	case AF_UNIX:
		s1 = ((struct sockaddr_un *) saddr->a )->sun_path;
		XPUSHs( sv_2mortal( newSVpvn( s1, strlen( s1 ) ) ) );
		break;
	case AF_BLUETOOTH:
		if( tv->s_proto == BTPROTO_L2CAP ) {
			l2a = (SOCKADDR_L2CAP *) saddr->a;
			r = my_ba2str( &l2a->bt_bdaddr, tmp );
			XPUSHs( sv_2mortal( newSVpv( tmp, r ) ) );
			XPUSHs( sv_2mortal( newSViv( l2a->bt_port ) ) );
		}
		break;
	case AF_INET:
		r = sprintf( tmp, "%u.%u.%u.%u",
			IP4( ((struct sockaddr_in *) saddr->a )->sin_addr.s_addr )
		);
		XPUSHs( sv_2mortal( newSVpv( tmp, r ) ) );
		XPUSHs( sv_2mortal( newSViv(
			ntohs( ((struct sockaddr_in *) saddr->a )->sin_port ) ) ) );
		break;
	case AF_INET6:
		s1 = (char *) &((struct sockaddr_in6 *) saddr->a )->sin6_addr;
		r = sprintf( tmp, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
			IP6( (uint16_t *) s1 )
		);
		XPUSHs( sv_2mortal( newSVpv( tmp, r ) ) );
		XPUSHs( sv_2mortal( newSViv(
			ntohs( ((struct sockaddr_in6 *) saddr->a )->sin6_port ) ) ) );
		break;
	}
	TV_UNLOCK( tv );
#line 1588 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_hostname); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_hostname)
{
    dXSARGS;
    if (items != 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_hostname(this, addr)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	addr = ST(1);
#line 1410 "Class.xs"
	my_thread_var_t *tv;
	my_sockaddr_t *saddr;
	const char *s1;
	STRLEN l1;
#ifndef SC_OLDNET
	struct addrinfo aih;
	struct addrinfo *ail = NULL;
	char host[NI_MAXHOST], serv[NI_MAXSERV];
	my_sockaddr_t sa2;
	int r;
#else
	struct hostent *he;
	struct in_addr ia4;
	struct in6_addr ia6;
#endif
#line 1621 "Class.c"
#line 1426 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	s1 = SvPV( addr, l1 );
	saddr = (my_sockaddr_t *) s1;
#ifndef SC_OLDNET
	if( l1 <= sizeof( int ) || l1 != MYSASIZE(*saddr) ) {
		memset( &aih, 0, sizeof( struct addrinfo ) );
		/*
		aih.ai_family = tv->s_domain;
		aih.ai_socktype = tv->s_type;
		aih.ai_protocol = tv->s_proto;
		*/
		r = getaddrinfo( s1, "", &aih, &ail );
		if( r != 0 ) {
			_debug( "getaddrinfo() failed %d\n", r );
			TV_ERRNO( tv, r );
			ST(0) = &PL_sv_undef;
		}
		sa2.l = (int) ail->ai_addrlen;
		memcpy( sa2.a, ail->ai_addr, ail->ai_addrlen );
		freeaddrinfo( ail );
		saddr = &sa2;
	}
	r = getnameinfo(
		(struct sockaddr *) saddr->a, saddr->l,
		host, sizeof( host ),
		serv, sizeof( serv ),
		NI_NUMERICSERV | NI_NAMEREQD
	);
	if( r != 0 ) {
		_debug( "getnameinfo() failed %d\n", r );
		TV_ERRNOLAST( tv );
		ST(0) = &PL_sv_undef;
	}
	ST(0) = sv_2mortal( newSVpvn( host, strlen( host ) ) );
#else
	GLOBAL_LOCK();
	if( l1 <= sizeof( int ) || l1 != MYSASIZE(*saddr) ) {
		if( tv->s_domain == AF_INET ) {
			if( inet_aton( s1, &ia4 ) == 0 ) {
				TV_ERROR( tv, "invalid address" );
				ST(0) = &PL_sv_undef;
				goto unlock;
			}
			he = gethostbyaddr( (const char *) &ia4, sizeof( ia4 ), AF_INET );
			if( he == NULL ) {
				TV_ERRNOLAST( tv );
				ST(0) = &PL_sv_undef;
				goto unlock;
			}
			TV_ERRNO( tv, 0 );
			ST(0) = sv_2mortal( newSVpvn( he->h_name, strlen( he->h_name ) ) );
		}
		else if( tv->s_domain == AF_INET6 ) {
#ifndef _WIN32
			if( inet_pton( AF_INET6, s1, &ia6 ) <= 0 ) {
				TV_ERROR( tv, "invalid address" );
				goto unlock;
			}
			he = gethostbyaddr( (const char *) &ia6, sizeof( ia6 ), AF_INET6 );
			if( he == NULL ) {
				TV_ERRNOLAST( tv );
				ST(0) = &PL_sv_undef;
				goto unlock;
			}
			TV_ERRNO( tv, 0 );
			ST(0) = sv_2mortal( newSVpvn( he->h_name, strlen( he->h_name ) ) );
#else
			TV_ERROR( tv, "not supported on this platform" );
			ST(0) = &PL_sv_undef;
#endif
		}
	}
	else {
		if( tv->s_domain == AF_INET ) {
			he = gethostbyaddr(
				(const char *) &((struct sockaddr_in *) saddr->a)->sin_addr,
				sizeof( ia4 ), AF_INET
			);
		}
		else if( tv->s_domain == AF_INET6 ) {
			he = gethostbyaddr(
				(const char *) &((struct sockaddr_in6 *) saddr->a)->sin6_addr,
				sizeof( ia6 ), AF_INET6
			);
		}
		else {
			TV_ERRNO( tv, 0 );
			ST(0) = &PL_sv_undef;
			goto unlock;
		}
		if( he == NULL ) {
			TV_ERRNOLAST( tv );
			ST(0) = &PL_sv_undef;
			goto unlock;
		}
		TV_ERRNO( tv, 0 );
		ST(0) = sv_2mortal( newSVpvn( he->h_name, strlen( he->h_name ) ) );
	}
unlock:
	GLOBAL_UNLOCK();
#endif
exit:
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 1729 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_hostaddr); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_hostaddr)
{
    dXSARGS;
    if (items != 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_hostaddr(this, name)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	name = ST(1);
#line 1543 "Class.xs"
	my_thread_var_t *tv;
	char *sname, tmp[40];
	STRLEN lname;
	int r;
#ifndef SC_OLDNET
	struct addrinfo aih;
	struct addrinfo *ail = NULL;
	void *p1;
#else
	struct hostent *he;
#endif
#line 1758 "Class.c"
#line 1555 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	sname = SvPVx( name, lname );
#ifndef SC_OLDNET
	memset( &aih, 0, sizeof( struct addrinfo ) );
	/*
	aih.ai_family = tv->s_domain;
	aih.ai_socktype = tv->s_type;
	aih.ai_protocol = tv->s_proto;
	*/
	r = getaddrinfo( sname, "", &aih, &ail );
	if( r != 0 ) {
		_debug( "getaddrinfo() failed %d\n", r );
		TV_ERRNO( tv, r );
		ST(0) = &PL_sv_undef;
		goto _exit;		
	}
	switch( ail->ai_family ) {
	case AF_INET:
		r = sprintf( tmp, "%u.%u.%u.%u",
			IP4( ((struct sockaddr_in *) ail->ai_addr )->sin_addr.s_addr )
		);
		ST(0) = sv_2mortal( newSVpvn( tmp, r ) );
		break;
	case AF_INET6:
		p1 = &((struct sockaddr_in6 *) ail->ai_addr )->sin6_addr;
		r = sprintf( tmp, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
			IP6( (uint16_t *) p1 )
		);
		ST(0) = sv_2mortal( newSVpvn( tmp, r ) );
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	freeaddrinfo( ail );
	TV_ERRNO( tv, 0 );
#else
	GLOBAL_LOCK();
	he = gethostbyname( sname );
	if( he == NULL ) {
		_debug( "gethostbyname() failed %d\n", Socket_errno() );
		TV_ERRNOLAST( tv );
		GLOBAL_UNLOCK();
		ST(0) = &PL_sv_undef;
		goto _exit;
	}
	switch( he->h_addrtype ) {
	case AF_INET:
		r = sprintf( tmp, "%u.%u.%u.%u",
			IP4( (*(struct in_addr*) he->h_addr).s_addr ) );
		ST(0) = sv_2mortal( newSVpvn( tmp, r ) );
		break;
	case AF_INET6:
		r = sprintf( tmp, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
			IP6( (uint16_t *) he->h_addr )
		);
		ST(0) = sv_2mortal( newSVpvn( tmp, r ) );
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	GLOBAL_UNLOCK();
	TV_ERRNO( tv, 0 );
#endif
_exit:
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 1828 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_set_blocking); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_set_blocking)
{
    dXSARGS;
    if (items < 1 || items > 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::set_blocking(this, value = 1)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	value;
#line 1634 "Class.xs"
	my_thread_var_t *tv;
	int r;
#line 1848 "Class.c"

	if (items < 2)
	    value = 1;
	else {
	    value = (int)SvIV(ST(1));
	}
#line 1637 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	r = Socket_setblocking( tv->sock, value );
	if( r == SOCKET_ERROR ) {
		TV_ERRNOLAST( tv );
		TV_UNLOCK( tv );
		XSRETURN_EMPTY;
	}
	TV_ERRNO( tv, 0 );
	tv->non_blocking = (BYTE) ! value;
	TV_UNLOCK( tv );
	XSRETURN_YES;
#line 1869 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_blocking); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_blocking)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_blocking(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 1660 "Class.xs"
	my_thread_var_t *tv;
#line 1887 "Class.c"
#line 1662 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	if( tv->non_blocking )
		ST(0) = &PL_sv_no;
	else
		ST(0) = &PL_sv_yes;
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 1898 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_set_reuseaddr); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_set_reuseaddr)
{
    dXSARGS;
    if (items < 1 || items > 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::set_reuseaddr(this, value = 1)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	value;
#line 1682 "Class.xs"
	int r;
#line 1917 "Class.c"

	if (items < 2)
	    value = 1;
	else {
	    value = (int)SvIV(ST(1));
	}
#line 1684 "Class.xs"
	r = Socket_setopt(
		this, SOL_SOCKET, SO_REUSEADDR, (void *) &value, sizeof( int )
	);
	if( r != SOCKET_ERROR )
		XSRETURN_YES;
	XSRETURN_EMPTY;
#line 1931 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_reuseaddr); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_reuseaddr)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_reuseaddr(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 1700 "Class.xs"
	int r;
	socklen_t l = sizeof( int );
	char val[sizeof( int )];
#line 1951 "Class.c"
#line 1704 "Class.xs"
	r = Socket_getopt( this, SOL_SOCKET, SO_REUSEADDR, val, &l );
	if( r != SOCKET_ERROR )
		XSRETURN_IV( *((int *) val) );
	XSRETURN_EMPTY;
#line 1957 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_set_broadcast); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_set_broadcast)
{
    dXSARGS;
    if (items < 1 || items > 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::set_broadcast(this, value = 1)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	value;
#line 1719 "Class.xs"
	int r;
#line 1976 "Class.c"

	if (items < 2)
	    value = 1;
	else {
	    value = (int)SvIV(ST(1));
	}
#line 1721 "Class.xs"
	r = Socket_setopt(
		this, SOL_SOCKET, SO_BROADCAST, (void *) &value, sizeof( int )
	);
	if( r != SOCKET_ERROR )
		XSRETURN_YES;
	XSRETURN_EMPTY;
#line 1990 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_broadcast); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_broadcast)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_broadcast(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 1737 "Class.xs"
	int r;
	socklen_t l = sizeof( int );
	char val[sizeof( int )];
#line 2010 "Class.c"
#line 1741 "Class.xs"
	r = Socket_getopt( this, SOL_SOCKET, SO_BROADCAST, val, &l );
	if( r != SOCKET_ERROR )
		XSRETURN_IV( *((int *) val) );
	XSRETURN_EMPTY;
#line 2016 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_set_rcvbuf_size); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_set_rcvbuf_size)
{
    dXSARGS;
    if (items != 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::set_rcvbuf_size(this, size)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	size = (int)SvIV(ST(1));
#line 1756 "Class.xs"
	int r;
#line 2035 "Class.c"
#line 1758 "Class.xs"
	r = Socket_setopt(
		this, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof( int )
	);
	if( r != SOCKET_ERROR )
		XSRETURN_YES;
	XSRETURN_EMPTY;
#line 2043 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_rcvbuf_size); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_rcvbuf_size)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_rcvbuf_size(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 1774 "Class.xs"
	int r;
	socklen_t l = sizeof( int );
	char val[sizeof( int )];
#line 2063 "Class.c"
#line 1778 "Class.xs"
	r = Socket_getopt( this, SOL_SOCKET, SO_RCVBUF, val, &l );
	if( r != SOCKET_ERROR )
		XSRETURN_IV( *((int *) val) );
	XSRETURN_EMPTY;
#line 2069 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_set_sndbuf_size); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_set_sndbuf_size)
{
    dXSARGS;
    if (items != 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::set_sndbuf_size(this, size)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	size = (int)SvIV(ST(1));
#line 1793 "Class.xs"
	int r;
#line 2088 "Class.c"
#line 1795 "Class.xs"
	r = Socket_setopt(
		this, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof( int )
	);
	if( r != SOCKET_ERROR )
		XSRETURN_YES;
	XSRETURN_EMPTY;
#line 2096 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_sndbuf_size); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_sndbuf_size)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_sndbuf_size(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 1811 "Class.xs"
	int r;
	socklen_t l = sizeof( int );
	char val[sizeof( int )];
#line 2116 "Class.c"
#line 1815 "Class.xs"
	r = Socket_getopt( this, SOL_SOCKET, SO_SNDBUF, val, &l );
	if( r != SOCKET_ERROR )
		XSRETURN_IV( *((int *) val) );
	XSRETURN_EMPTY;
#line 2122 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_set_tcp_nodelay); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_set_tcp_nodelay)
{
    dXSARGS;
    if (items < 1 || items > 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::set_tcp_nodelay(this, value = 1)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	value;
#line 1830 "Class.xs"
	int r;
#line 2141 "Class.c"

	if (items < 2)
	    value = 1;
	else {
	    value = (int)SvIV(ST(1));
	}
#line 1832 "Class.xs"
	r = Socket_setopt(
		this, IPPROTO_TCP, TCP_NODELAY, (void *) &value, sizeof( int )
	);
	if( r != SOCKET_ERROR )
		XSRETURN_YES;
	XSRETURN_EMPTY;
#line 2155 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_tcp_nodelay); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_tcp_nodelay)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_tcp_nodelay(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 1848 "Class.xs"
	int r;
	socklen_t l = sizeof( int );
	char val[sizeof( int )];
#line 2175 "Class.c"
#line 1852 "Class.xs"
	r = Socket_getopt( this, IPPROTO_TCP, TCP_NODELAY, val, &l );
	if( r != SOCKET_ERROR )
		XSRETURN_IV( *((int *) val) );
	XSRETURN_EMPTY;
#line 2181 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_set_option); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_set_option)
{
    dXSARGS;
    if (items < 4)
	Perl_croak(aTHX_ "Usage: Socket::Class::set_option(this, level, optname, value, ...)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	level = (int)SvIV(ST(1));
	int	optname = (int)SvIV(ST(2));
	SV *	value = ST(3);
#line 1869 "Class.xs"
	int r;
	STRLEN len;
	const void *val;
	char tmp[20];
#line 2205 "Class.c"
#line 1874 "Class.xs"
	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 = &r;
		len = sizeof( int );
	}
	else {
		val = SvPVbyte( value, len );
	}
_set:
	r = Socket_setopt( this, level, optname, val, (socklen_t) len );
	if( r != SOCKET_ERROR )
		XSRETURN_YES;
	XSRETURN_EMPTY;
#line 2266 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_option); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_option)
{
    dXSARGS;
    if (items != 3)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_option(this, level, optname)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	level = (int)SvIV(ST(1));
	int	optname = (int)SvIV(ST(2));
#line 1945 "Class.xs"
	my_thread_var_t *tv;
	char tmp[20];
	int r;
	socklen_t l = sizeof( tmp );
#line 2289 "Class.c"
#line 1950 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	l = sizeof( tmp );
	r = getsockopt( tv->sock, level, optname, tmp, &l );
	if( r == SOCKET_ERROR ) {
		TV_ERRNOLAST( tv );
		goto _set;
	}
	TV_ERRNO( tv, 0 );
	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
			printf( "optlen %d\n", l );
			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:
	TV_UNLOCK( tv );
#line 2358 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_set_timeout); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_set_timeout)
{
    dXSARGS;
    if (items != 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::set_timeout(this, ms)");
    SP -= items;
    {
	SV *	this = ST(0);
	double	ms = (double)SvNV(ST(1));
#line 2028 "Class.xs"
	my_thread_var_t *tv;
#line 2377 "Class.c"
#line 2030 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	tv->timeout.tv_sec = (long) (ms / 1000);
	tv->timeout.tv_usec = (long) (ms * 1000) % 1000000;
	TV_UNLOCK( tv );
	XSRETURN_YES;
#line 2386 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_get_timeout); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_get_timeout)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::get_timeout(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2047 "Class.xs"
	my_thread_var_t *tv;
#line 2404 "Class.c"
#line 2049 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	XSRETURN_NV( tv->timeout.tv_sec * 1000 + tv->timeout.tv_usec / 1000 );
#line 2409 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_is_readable); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_is_readable)
{
    dXSARGS;
    if (items < 1 || items > 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::is_readable(this, timeout = NULL)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	timeout;
#line 2063 "Class.xs"
	my_thread_var_t *tv;
	fd_set fd_socks;
	struct timeval t;
	int ret;
	double ms;
#line 2432 "Class.c"

	if (items < 2)
	    timeout = NULL;
	else {
	    timeout = ST(1);
	}
#line 2069 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	FD_ZERO( &fd_socks );
	FD_SET( tv->sock, &fd_socks );
	if( timeout != NULL ) {
		ms = SvNV( timeout );
		t.tv_sec = (long) (ms / 1000);
		t.tv_usec = (long) (ms * 1000) % 1000000;
		ret = select(
			(int) (tv->sock + 1), &fd_socks, NULL, NULL, &t
		);
	}
	else {
		ret = select(
			(int) (tv->sock + 1), &fd_socks, NULL, NULL, NULL
		);
	}
	if( ret < 0 ) {
		TV_ERRNOLAST( tv );
		_debug( "is_readable error %u\n", tv->last_errno );
		tv->state = SOCK_STATE_ERROR;
		ST(0) = &PL_sv_undef;
	}
	else {
		TV_ERRNO( tv, 0 );
		ST(0) = ret ? &PL_sv_yes : &PL_sv_no;
	}
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2470 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_is_writable); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_is_writable)
{
    dXSARGS;
    if (items < 1 || items > 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::is_writable(this, timeout = NULL)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	timeout;
#line 2110 "Class.xs"
	my_thread_var_t *tv;
	fd_set fd_socks;
	struct timeval t;
	int ret;
	double ms;
#line 2493 "Class.c"

	if (items < 2)
	    timeout = NULL;
	else {
	    timeout = ST(1);
	}
#line 2116 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	FD_ZERO( &fd_socks );
	FD_SET( tv->sock, &fd_socks );
	if( timeout != NULL ) {
		ms = SvNV( timeout );
		t.tv_sec = (long) (ms / 1000);
		t.tv_usec = (long) (ms * 1000) % 1000000;
		ret = select(
			(int) ( tv->sock + 1 ), NULL, &fd_socks, NULL, &t
		);
	}
	else {
		ret = select(
			(int) ( tv->sock + 1 ), NULL, &fd_socks, NULL, NULL
		);
	}
	if( ret < 0 ) {
		TV_ERRNOLAST( tv );
		_debug( "is_writable error %u\n", tv->last_errno );
		tv->state = SOCK_STATE_ERROR;
		ST(0) = &PL_sv_undef;
	}
	else {
		TV_ERRNO( tv, 0 );
		ST(0) = ret ? &PL_sv_yes : &PL_sv_no;
	}
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2531 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_select); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_select)
{
    dXSARGS;
    if (items < 1 || items > 5)
	Perl_croak(aTHX_ "Usage: Socket::Class::select(this, read = NULL, write = NULL, except = NULL, timeout = NULL)");
    SP -= items;
    {
	SV *	this = ST(0);
	SV *	read;
	SV *	write;
	SV *	except;
	SV *	timeout;
#line 2160 "Class.xs"
	my_thread_var_t *tv;
	fd_set fdr, fdw, fde;
	struct timeval t, *pt;
	int ret, dr, dw, de;
	double ms;
#line 2557 "Class.c"

	if (items < 2)
	    read = NULL;
	else {
	    read = ST(1);
	}

	if (items < 3)
	    write = NULL;
	else {
	    write = ST(2);
	}

	if (items < 4)
	    except = NULL;
	else {
	    except = ST(3);
	}

	if (items < 5)
	    timeout = NULL;
	else {
	    timeout = ST(4);
	}
#line 2166 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	if( read == NULL )
		dr = 0;
	else if( (dr = SvTRUE( read )) ) {
		FD_ZERO( &fdr );
		FD_SET( tv->sock, &fdr );
	}
	if( write == NULL )
		dw = 0;
	else if( (dw = SvTRUE( write )) ) {
		FD_ZERO( &fdw );
		FD_SET( tv->sock, &fdw );
	}
	if( except == NULL )
		de = 0;
	else if( (de = SvTRUE( except )) ) {
		FD_ZERO( &fde );
		FD_SET( tv->sock, &fde );
	}
	if( timeout == NULL )
		pt = NULL;
	else {
		ms = SvNV( timeout );
		t.tv_sec = (long) (ms / 1000);
		t.tv_usec = (long) (ms * 1000) % 1000000;
		pt = &t;
	}
	ret = select(
		(int) (tv->sock + 1), (dr ? &fdr : NULL), (dw ? &fdw : NULL),
		(de ? &fde : NULL), pt
	);
	if( ret < 0 ) {
		TV_ERRNOLAST( tv );
		_debug( "select error %u\n", tv->last_errno );
		tv->state = SOCK_STATE_ERROR;
		ST(0) = &PL_sv_undef;
	}
	else {
		TV_ERRNO( tv, 0 );
		ST(0) = sv_2mortal( newSViv( ret ) );
		if( dr && ! SvREADONLY( read ) )
			sv_setiv( read, FD_ISSET( tv->sock, &fdr ) ? 1 : 0 );
		if( dw && ! SvREADONLY( write ) )
			sv_setiv( write, FD_ISSET( tv->sock, &fdw ) ? 1 : 0 );
		if( de && ! SvREADONLY( except ) )
			sv_setiv( except, FD_ISSET( tv->sock, &fde ) ? 1 : 0 );
	}
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2634 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_wait); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_wait)
{
    dXSARGS;
    if (items != 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::wait(this, timeout)");
    SP -= items;
    {
	SV *	this = ST(0);
	unsigned long	timeout = (unsigned long)SvUV(ST(1));
#line 2228 "Class.xs"
#ifndef _WIN32
	struct timeval t;
#endif
#line 2655 "Class.c"
#line 2232 "Class.xs"
#ifdef _WIN32
	Sleep( timeout );
#else
	t.tv_sec = (long) (timeout / 1000);
	t.tv_usec = (long) (timeout * 1000) % 1000000;
	select( 0, NULL, NULL, NULL, &t );
#endif
#line 2664 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_handle); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_handle)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::handle(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2249 "Class.xs"
	my_thread_var_t *tv;
#line 2682 "Class.c"
#line 2251 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	ST(0) = sv_2mortal( newSViv( tv->sock ) );
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2690 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_state); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_state)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::state(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2267 "Class.xs"
	my_thread_var_t *tv;
#line 2708 "Class.c"
#line 2269 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	ST(0) = sv_2mortal( newSViv( tv->state ) );
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2716 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_local_addr); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_local_addr)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::local_addr(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2285 "Class.xs"
	my_thread_var_t *tv;
	char tmp[40];
	int r;
	void *p1;
#line 2737 "Class.c"
#line 2290 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	switch( tv->s_domain ) {
	case AF_INET:
		r = sprintf( tmp, "%u.%u.%u.%u",
			IP4( ((struct sockaddr_in *) tv->l_addr.a )->sin_addr.s_addr )
		);
		ST(0) = sv_2mortal( newSVpv( tmp, r ) );
		break;
	case AF_INET6:
		p1 = &((struct sockaddr_in6 *) tv->l_addr.a )->sin6_addr;
		r = sprintf( tmp, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
			IP6( (uint16_t *) p1 )
		);
		ST(0) = sv_2mortal( newSVpv( tmp, r ) );
		break;
	case AF_BLUETOOTH:
		r = my_ba2str(
			(bdaddr_t *) &tv->l_addr.a[sizeof(sa_family_t)], tmp );
		ST(0) = sv_2mortal( newSVpv( tmp, r ) );
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2766 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_local_path); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_local_path)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::local_path(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2327 "Class.xs"
	my_thread_var_t *tv;
	char *s1;
#line 2785 "Class.c"
#line 2330 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	switch( tv->s_domain ) {
	case AF_UNIX:
		s1 = ((struct sockaddr_un *) tv->l_addr.a )->sun_path;
		ST(0) = sv_2mortal( newSVpv( s1, strlen( s1 ) ) );
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2800 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_local_port); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_local_port)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::local_port(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2353 "Class.xs"
	my_thread_var_t *tv;
#line 2818 "Class.c"
#line 2355 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	switch( tv->s_domain ) {
	case AF_INET:
		ST(0) = sv_2mortal( newSViv(
			ntohs( ((struct sockaddr_in *) tv->l_addr.a )->sin_port ) ) );
		break;
	case AF_INET6:
		ST(0) = sv_2mortal( newSViv(
			ntohs( ((struct sockaddr_in6 *) tv->l_addr.a )->sin6_port ) ) );
		break;
	case AF_BLUETOOTH:
		switch( tv->s_proto ) {
		case BTPROTO_RFCOMM:
			ST(0) = sv_2mortal(
				newSViv( ((SOCKADDR_RFCOMM *) tv->l_addr.a)->bt_port ) );
			break;
		case BTPROTO_L2CAP:
			ST(0) = sv_2mortal(
				newSViv( ((SOCKADDR_L2CAP *) tv->l_addr.a)->bt_port ) );
			break;
		default:
			ST(0) = &PL_sv_undef;
		}
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2851 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_remote_addr); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_remote_addr)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::remote_addr(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2396 "Class.xs"
	my_thread_var_t *tv;
	char tmp[40];
	void *p1;
	int r;
#line 2872 "Class.c"
#line 2401 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	switch( tv->s_domain ) {
	case AF_INET:
		r = sprintf( tmp, "%u.%u.%u.%u",
			IP4( ((struct sockaddr_in *) tv->r_addr.a )->sin_addr.s_addr )
		);
		ST(0) = sv_2mortal( newSVpv( tmp, r ) );
		break;
	case AF_INET6:
		p1 = &((struct sockaddr_in6 *) tv->r_addr.a )->sin6_addr;
		r = sprintf( tmp, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
			IP6( (uint16_t *) p1 )
		);
		ST(0) = sv_2mortal( newSVpv( tmp, r ) );
		break;
	case AF_BLUETOOTH:
		r = my_ba2str(
			(bdaddr_t *) &tv->r_addr.a[sizeof(sa_family_t)], tmp );
		ST(0) = sv_2mortal( newSVpv( tmp, r ) );
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2901 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_remote_path); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_remote_path)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::remote_path(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2438 "Class.xs"
	my_thread_var_t *tv;
	char *s1;
#line 2920 "Class.c"
#line 2441 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	switch( tv->s_domain ) {
	case AF_UNIX:
		s1 = ((struct sockaddr_un *) tv->r_addr.a )->sun_path;
		ST(0) = sv_2mortal( newSVpv( s1, strlen( s1 ) ) );
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2935 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_remote_port); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_remote_port)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::remote_port(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2464 "Class.xs"
	my_thread_var_t *tv;
#line 2953 "Class.c"
#line 2466 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	switch( tv->s_domain ) {
	case AF_INET:
		ST(0) = sv_2mortal( newSViv(
			ntohs( ((struct sockaddr_in *) tv->r_addr.a )->sin_port ) ) );
		break;
	case AF_INET6:
		ST(0) = sv_2mortal( newSViv(
			ntohs( ((struct sockaddr_in6 *) tv->r_addr.a )->sin6_port ) ) );
		break;
	case AF_BLUETOOTH:
		switch( tv->s_proto ) {
		case BTPROTO_RFCOMM:
			ST(0) = sv_2mortal(
				newSViv( ((SOCKADDR_RFCOMM *) tv->r_addr.a)->bt_port ) );
			break;
		case BTPROTO_L2CAP:
			ST(0) = sv_2mortal(
				newSViv( ((SOCKADDR_L2CAP *) tv->r_addr.a)->bt_port ) );
			break;
		default:
			ST(0) = &PL_sv_undef;
		}
		break;
	default:
		ST(0) = &PL_sv_undef;
	}
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 2986 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_to_string); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_to_string)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::to_string(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2507 "Class.xs"
	my_thread_var_t *tv;
	char tmp[1024], *s1;
	void *p1;
	int r;
#line 3007 "Class.c"
#line 2512 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	s1 = my_strcpy( tmp, "SOCKET(ID=" );
	if( tv->sock != INVALID_SOCKET )
		s1 = my_itoa( s1, (long) tv->sock, 10 );
	else
		s1 = my_strcpy( s1, "NONE" );
	s1 = my_strcpy( s1, ";DOMAIN=" );
	switch( tv->s_domain ) {
		case AF_INET:
			s1 = my_strcpy( s1, "INET" );
			break;
		case AF_INET6:
			s1 = my_strcpy( s1, "INET6" );
			break;
		case AF_UNIX:
			s1 = my_strcpy( s1, "UNIX" );
			break;
		case AF_BLUETOOTH:
			s1 = my_strcpy( s1, "BTH" );
			break;
		default:
			s1 = my_itoa( s1, tv->s_domain, 10 );
			break;
	}
	s1 = my_strcpy( s1, ";TYPE=" );
	switch( tv->s_type ) {
		case SOCK_STREAM:
			s1 = my_strcpy( s1, "STREAM" );
			break;
		case SOCK_DGRAM:
			s1 = my_strcpy( s1, "DGRAM" );
			break;
		case SOCK_RAW:
			s1 = my_strcpy( s1, "RAW" );
			break;
		default:
			s1 = my_itoa( s1, tv->s_type, 10 );
			break;
	}
	s1 = my_strcpy( s1, ";PROTO=" );
	switch( tv->s_proto ) {
		case IPPROTO_TCP:
			s1 = my_strcpy( s1, "TCP" );
			break;
		case IPPROTO_UDP:
			s1 = my_strcpy( s1, "UDP" );
			break;
		case IPPROTO_ICMP:
			s1 = my_strcpy( s1, "ICMP" );
			break;
		default:
			s1 = my_itoa( s1, tv->s_proto, 10 );
			break;
	}
	if( tv->l_addr.l ) {
		switch( tv->s_domain ) {
		case AF_INET:
			r = sprintf(
				s1,
				";LOCAL=%u.%u.%u.%u:%u",
				IPPORT4(
					((struct sockaddr_in *) tv->l_addr.a )->sin_addr.s_addr,
					((struct sockaddr_in *) tv->l_addr.a )->sin_port
				)
			);
			s1 += (size_t ) r;
			break;
		case AF_INET6:
			p1 = &((struct sockaddr_in6 *) tv->l_addr.a )->sin6_addr;
			r = sprintf(
				s1,
				";LOCAL=[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%u",
				IPPORT6(
					(uint16_t *) p1,
					((struct sockaddr_in6 *) tv->l_addr.a )->sin6_port
				)
			);
			s1 += (size_t ) r;
			break;
		case AF_UNIX:
			s1 = my_strcpy( s1, ";LOCAL=" );
			s1 = my_strcpy( s1,
				((struct sockaddr_un *) tv->l_addr.a )->sun_path );
			break;
		case AF_BLUETOOTH:
			s1 = my_strcpy( s1, ";LOCAL=" );
			s1 += my_ba2str(
				(bdaddr_t *) &tv->l_addr.a[sizeof(sa_family_t)], s1 );
			break;
		}
	}
	if( tv->r_addr.l ) {
		switch( tv->s_domain ) {
		case AF_INET:
			r = sprintf(
				s1,
				";REMOTE=%u.%u.%u.%u:%u",
				IPPORT4(
					((struct sockaddr_in *) tv->r_addr.a )->sin_addr.s_addr,
					((struct sockaddr_in *) tv->r_addr.a )->sin_port
				)
			);
			s1 += (size_t ) r;
			break;
		case AF_INET6:
			p1 = &((struct sockaddr_in6 *) tv->r_addr.a )->sin6_addr;
			r = sprintf(
				s1,
				";REMOTE=[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%u",
				IPPORT6(
					(uint16_t *) p1,
					((struct sockaddr_in6 *) tv->r_addr.a )->sin6_port
				)
			);
			s1 += (size_t ) r;
			break;
		case AF_UNIX:
			s1 = my_strcpy( s1, ";REMOTE=" );
			s1 = my_strcpy( s1,
				((struct sockaddr_un *) tv->r_addr.a )->sun_path );
			break;
		case AF_BLUETOOTH:
			s1 = my_strcpy( s1, ";REMOTE=" );
			s1 += my_ba2str(
				(bdaddr_t *) &tv->r_addr.a[sizeof(sa_family_t)], s1 );
			break;
		}
	}
	*s1 ++ = ')';
	TV_UNLOCK( tv );
	ST(0) = sv_2mortal( newSVpv( tmp, (size_t) (s1 - tmp) ) );
	XSRETURN( 1 );
#line 3143 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_is_error); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_is_error)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::is_error(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2656 "Class.xs"
	my_thread_var_t *tv;
#line 3161 "Class.c"
#line 2658 "Class.xs"
	if( (tv = my_thread_var_find( this )) == NULL )
		XSRETURN_EMPTY;
	TV_LOCK( tv );
	ST(0) = (tv->state == SOCK_STATE_ERROR) ? &PL_sv_yes : &PL_sv_no;
	TV_UNLOCK( tv );
	XSRETURN( 1 );
#line 3169 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_errno); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_errno)
{
    dXSARGS;
    if (items != 1)
	Perl_croak(aTHX_ "Usage: Socket::Class::errno(this)");
    SP -= items;
    {
	SV *	this = ST(0);
#line 2674 "Class.xs"
	my_thread_var_t *tv;
#line 3187 "Class.c"
#line 2676 "Class.xs"
	if( (tv = my_thread_var_find( this )) != NULL ) {
		TV_LOCK( tv );
		ST(0) = sv_2mortal( newSViv( tv->last_errno ) );
		TV_UNLOCK( tv );
		XSRETURN( 1 );
	}
	GLOBAL_LOCK();
	ST(0) = sv_2mortal( newSViv( global.last_errno ) );
	GLOBAL_UNLOCK();
	XSRETURN( 1 );
#line 3199 "Class.c"
	PUTBACK;
	return;
    }
}


XS(XS_Socket__Class_error); /* prototype to pass -Wmissing-prototypes */
XS(XS_Socket__Class_error)
{
    dXSARGS;
    if (items < 1 || items > 2)
	Perl_croak(aTHX_ "Usage: Socket::Class::error(this, code = 0)");
    SP -= items;
    {
	SV *	this = ST(0);
	int	code;
#line 2697 "Class.xs"
	my_thread_var_t *tv;
#line 3218 "Class.c"

	if (items < 2)
	    code = 0;
	else {
	    code = (int)SvIV(ST(1));
	}
#line 2699 "Class.xs"
	if( (tv = my_thread_var_find( this )) != NULL ) {
		TV_LOCK( tv );
		if( ! code )
			code = tv->last_errno;
		if( code > 0 )
			Socket_error(
				tv->last_error, sizeof( tv->last_error ), code
			);
		ST(0) = sv_2mortal( newSVpv( tv->last_error, 0 ) );
		TV_UNLOCK( tv );
		XSRETURN( 1 );
	}
	GLOBAL_LOCK();
	if( ! code )
		code = global.last_errno;
	if( code > 0 )
		Socket_error(
			global.last_error, sizeof( global.last_error ), code
		);
	ST(0) = sv_2mortal( newSVpv( global.last_error, 0 ) );
	GLOBAL_UNLOCK();
	XSRETURN( 1 );
#line 3248 "Class.c"
	PUTBACK;
	return;
    }
}

#ifdef __cplusplus
extern "C"
#endif
XS(boot_Socket__Class); /* prototype to pass -Wmissing-prototypes */
XS(boot_Socket__Class)
{
    dXSARGS;
    char* file = __FILE__;

    XS_VERSION_BOOTCHECK ;

        newXS("Socket::Class::END", XS_Socket__Class_END, file);
#if XSubPPtmpAAAA
        newXS("Socket::Class::CLONE_SKIP", XS_Socket__Class_CLONE_SKIP, file);
#endif
        newXS("Socket::Class::DESTROY", XS_Socket__Class_DESTROY, file);
        newXS("Socket::Class::new", XS_Socket__Class_new, file);
        newXS("Socket::Class::connect", XS_Socket__Class_connect, file);
        newXS("Socket::Class::free", XS_Socket__Class_free, file);
        newXS("Socket::Class::close", XS_Socket__Class_close, file);
        newXS("Socket::Class::shutdown", XS_Socket__Class_shutdown, file);
        newXS("Socket::Class::bind", XS_Socket__Class_bind, file);
        newXS("Socket::Class::listen", XS_Socket__Class_listen, file);
        newXS("Socket::Class::accept", XS_Socket__Class_accept, file);
        newXS("Socket::Class::recv", XS_Socket__Class_recv, file);
        newXS("Socket::Class::send", XS_Socket__Class_send, file);
        newXS("Socket::Class::recvfrom", XS_Socket__Class_recvfrom, file);
        newXS("Socket::Class::sendto", XS_Socket__Class_sendto, file);
        newXS("Socket::Class::read", XS_Socket__Class_read, file);
        newXS("Socket::Class::write", XS_Socket__Class_write, file);
        newXS("Socket::Class::writeline", XS_Socket__Class_writeline, file);
        newXS("Socket::Class::print", XS_Socket__Class_print, file);
        newXS("Socket::Class::readline", XS_Socket__Class_readline, file);
        newXS("Socket::Class::pack_addr", XS_Socket__Class_pack_addr, file);
        newXS("Socket::Class::unpack_addr", XS_Socket__Class_unpack_addr, file);
        newXS("Socket::Class::get_hostname", XS_Socket__Class_get_hostname, file);
        newXS("Socket::Class::get_hostaddr", XS_Socket__Class_get_hostaddr, file);
        newXS("Socket::Class::set_blocking", XS_Socket__Class_set_blocking, file);
        newXS("Socket::Class::get_blocking", XS_Socket__Class_get_blocking, file);
        newXS("Socket::Class::set_reuseaddr", XS_Socket__Class_set_reuseaddr, file);
        newXS("Socket::Class::get_reuseaddr", XS_Socket__Class_get_reuseaddr, file);
        newXS("Socket::Class::set_broadcast", XS_Socket__Class_set_broadcast, file);
        newXS("Socket::Class::get_broadcast", XS_Socket__Class_get_broadcast, file);
        newXS("Socket::Class::set_rcvbuf_size", XS_Socket__Class_set_rcvbuf_size, file);
        newXS("Socket::Class::get_rcvbuf_size", XS_Socket__Class_get_rcvbuf_size, file);
        newXS("Socket::Class::set_sndbuf_size", XS_Socket__Class_set_sndbuf_size, file);
        newXS("Socket::Class::get_sndbuf_size", XS_Socket__Class_get_sndbuf_size, file);
        newXS("Socket::Class::set_tcp_nodelay", XS_Socket__Class_set_tcp_nodelay, file);
        newXS("Socket::Class::get_tcp_nodelay", XS_Socket__Class_get_tcp_nodelay, file);
        newXS("Socket::Class::set_option", XS_Socket__Class_set_option, file);
        newXS("Socket::Class::get_option", XS_Socket__Class_get_option, file);
        newXS("Socket::Class::set_timeout", XS_Socket__Class_set_timeout, file);
        newXS("Socket::Class::get_timeout", XS_Socket__Class_get_timeout, file);
        newXS("Socket::Class::is_readable", XS_Socket__Class_is_readable, file);
        newXS("Socket::Class::is_writable", XS_Socket__Class_is_writable, file);
        newXS("Socket::Class::select", XS_Socket__Class_select, file);
        newXS("Socket::Class::wait", XS_Socket__Class_wait, file);
        newXS("Socket::Class::handle", XS_Socket__Class_handle, file);
        newXS("Socket::Class::state", XS_Socket__Class_state, file);
        newXS("Socket::Class::local_addr", XS_Socket__Class_local_addr, file);
        newXS("Socket::Class::local_path", XS_Socket__Class_local_path, file);
        newXS("Socket::Class::local_port", XS_Socket__Class_local_port, file);
        newXS("Socket::Class::remote_addr", XS_Socket__Class_remote_addr, file);
        newXS("Socket::Class::remote_path", XS_Socket__Class_remote_path, file);
        newXS("Socket::Class::remote_port", XS_Socket__Class_remote_port, file);
        newXS("Socket::Class::to_string", XS_Socket__Class_to_string, file);
        newXS("Socket::Class::is_error", XS_Socket__Class_is_error, file);
        newXS("Socket::Class::errno", XS_Socket__Class_errno, file);
        newXS("Socket::Class::error", XS_Socket__Class_error, file);

    /* Initialisation Section */

#line 10 "Class.xs"
{
#ifdef _WIN32
	WSADATA wsaData;
	int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
	if( iResult != NO_ERROR )
		Perl_croak( aTHX_ "Error at WSAStartup()" );
#endif
	memset( global.first_thread, 0, sizeof( global.first_thread ) );
	memset( global.last_thread, 0, sizeof( global.last_thread ) );
	global.destroyed = 0;
#ifdef SC_THREADS
	MUTEX_INIT( &global.thread_lock );
#endif
#ifdef SC_OLDNET
	sv_setiv( get_sv( __PACKAGE__ "::OLDNET", 1 ), 1 );
#endif
#ifdef SC_HAS_BLUETOOTH
	sv_setiv( get_sv( __PACKAGE__ "::BLUETOOTH", 1 ), 1 );
	boot_Socket__Class__BT();
#endif
}

#if XSubPPtmpAAAA
#endif
#line 3351 "Class.c"

    /* End of Initialisation Section */

    XSRETURN_YES;
}

