Ejemplo n.º 1
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_Loopback_OpenSocket
*/
static qboolean NET_Loopback_OpenSocket( socket_t *socket, const netadr_t *address, qboolean server )
{
    int i;

    assert( address );

    if( address->type != NA_LOOPBACK )
    {
        NET_SetErrorString( "Invalid address" );
        return qfalse;
    }

    for( i = 0; i < 2; i++ )
    {
        if( !loopbacks[i].open )
            break;
    }
    if( i == 2 )
    {
        NET_SetErrorString( "Both loopback sockets already open" );
        return qfalse;
    }

    memset( &loopbacks[i], 0, sizeof( loopbacks[i] ) );
    loopbacks[i].open = qtrue;

    socket->open = qtrue;
    socket->handle = i;

    socket->type = SOCKET_LOOPBACK;
    socket->address = *address;
    socket->server = server;

    return qtrue;
}
Ejemplo n.º 2
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_Send
*/
int NET_Send( const socket_t *socket, const void *data, size_t length, const netadr_t *address )
{
    assert( socket->open );

    if( !socket->open )
        return qfalse;

    if( address->type == NA_NOTRANSMIT )
        return qtrue;

    switch( socket->type )
    {
    case SOCKET_LOOPBACK:
    case SOCKET_UDP:
        NET_SetErrorString( "Operation not supported by the socket type" );
        return -1;

#ifdef TCP_SUPPORT
    case SOCKET_TCP:
        return NET_TCP_Send( socket, data, length );
#endif

    default:
        assert( qfalse );
        NET_SetErrorString( "Unknown socket type" );
        return -1;
    }
}
Ejemplo n.º 3
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_Get
*
* 1	ok
* 0	no data ready
* -1	error
*/
int NET_Get( const socket_t *socket, netadr_t *address, void *data, size_t length )
{
    assert( socket->open );

    if( !socket->open )
        return -1;

    switch( socket->type )
    {
    case SOCKET_LOOPBACK:
    case SOCKET_UDP:
        NET_SetErrorString( "Operation not supported by the socket type" );
        return -1;

#ifdef TCP_SUPPORT
    case SOCKET_TCP:
        return NET_TCP_Get( socket, address, data, length );
#endif

    default:
        assert( qfalse );
        NET_SetErrorString( "Unknown socket type" );
        return -1;
    }
}
Ejemplo n.º 4
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_SetErrorStringFromLastError
*/
void NET_SetErrorStringFromLastError( const char *function )
{
    const char* errorstring = GetLastErrorString();
    if( function )
    {
        NET_SetErrorString( "%s: %s", function, errorstring );
    }
    else
    {
        NET_SetErrorString( "%s", errorstring );
    }
}
Ejemplo n.º 5
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* StringToSockaddress
*/
static qboolean StringToSockaddress( const char *s, struct sockaddr_storage *sadr )
{
    char addr_copy [128];
    char port_copy [8];
    const char *str;
    int addr_family;

    assert( s );
    assert( sadr );

    if( strlen( s ) >= sizeof( addr_copy ) / sizeof( char ) )
    {
        NET_SetErrorString( "String too long" );
        return qfalse;
    }

    str = ( s[0] == '\0' ? "0.0.0.0" : s );
    if( ParseAddressString( str, addr_copy, sizeof( addr_copy ), port_copy, sizeof( port_copy ), &addr_family ) )
    {
        struct addrinfo hints;
        struct addrinfo* addrinf = NULL;
        int err;

        memset( &hints, 0, sizeof ( hints ) );
        hints.ai_family = addr_family;
        hints.ai_socktype = SOCK_DGRAM;

        err = getaddrinfo( addr_copy, port_copy, &hints, &addrinf );
        if ( err == 0 && addrinf != NULL )
        {
            memcpy( sadr, addrinf->ai_addr, addrinf->ai_addrlen );
            freeaddrinfo( addrinf );
            return qtrue;
        }
        else
        {
            NET_SetErrorString( "Host not found" );
        }

        if ( addrinf != NULL )
            freeaddrinfo ( addrinf );
    }
    else
    {
        NET_SetErrorString( "Invalid address string" );
    }

    return qfalse;
}
Ejemplo n.º 6
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_SendPacket
*/
qboolean NET_SendPacket( const socket_t *socket, const void *data, size_t length, const netadr_t *address )
{
    assert( socket->open );

    if( !socket->open )
        return qfalse;

    if( address->type == NA_NOTRANSMIT )
        return qtrue;

    switch( socket->type )
    {
    case SOCKET_LOOPBACK:
        return NET_Loopback_SendPacket( socket, data, length, address );

    case SOCKET_UDP:
        return NET_UDP_SendPacket( socket, data, length, address );

#ifdef TCP_SUPPORT
    case SOCKET_TCP:
        return NET_TCP_SendPacket( socket, data, length );
#endif

    default:
        assert( qfalse );
        NET_SetErrorString( "Unknown socket type" );
        return qfalse;
    }
}
Ejemplo n.º 7
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_SendLoopbackPacket
*/
static qboolean NET_Loopback_SendPacket( const socket_t *socket, const void *data, size_t length,
        const netadr_t *address )
{
    int i;
    loopback_t *loop;

    assert( socket->open && socket->type == SOCKET_LOOPBACK );
    assert( data );
    assert( length > 0 );
    assert( address );

    if( address->type != NA_LOOPBACK )
    {
        NET_SetErrorString( "Invalid address" );
        return qfalse;
    }

    loop = &loopbacks[socket->handle^1];

    i = loop->send & ( MAX_LOOPBACK - 1 );
    loop->send++;

    memcpy( loop->msgs[i].data, data, length );
    loop->msgs[i].datalen = length;

    return qtrue;
}
Ejemplo n.º 8
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_GetPacket
*
* 1	ok
* 0	not ready
* -1	error
*/
int NET_GetPacket( const socket_t *socket, netadr_t *address, msg_t *message )
{
    assert( socket->open );

    if( !socket->open )
        return -1;

    switch( socket->type )
    {
    case SOCKET_LOOPBACK:
        return NET_Loopback_GetPacket( socket, address, message );

    case SOCKET_UDP:
        return NET_UDP_GetPacket( socket, address, message );

#ifdef TCP_SUPPORT
    case SOCKET_TCP:
        return NET_TCP_GetPacket( socket, address, message );
#endif

    default:
        assert( qfalse );
        NET_SetErrorString( "Unknown socket type" );
        return -1;
    }
}
Ejemplo n.º 9
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_CloseSocket
*/
void NET_CloseSocket( socket_t *socket )
{
    if( !socket->open )
        return;

    switch( socket->type )
    {
    case SOCKET_LOOPBACK:
        NET_Loopback_CloseSocket( socket );
        break;

    case SOCKET_UDP:
        NET_UDP_CloseSocket( socket );
        break;

#ifdef TCP_SUPPORT
    case SOCKET_TCP:
        NET_TCP_CloseSocket( socket );
        break;
#endif

    default:
        assert( qfalse );
        NET_SetErrorString( "Unknown socket type" );
        break;
    }
}
Ejemplo n.º 10
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* SockaddressToAddress
*/
static qboolean SockaddressToAddress( const struct sockaddr *s, netadr_t *address )
{
    assert( s );
    assert( address );

    switch( s->sa_family )
    {
    case AF_INET:
    {
        const struct sockaddr_in *sadr_in = (const struct sockaddr_in *)s;
        netadr_ipv4_t *na4 = &address->address.ipv4;

        address->type = NA_IP;
        *(int*)na4->ip = sadr_in->sin_addr.s_addr;
        na4->port = sadr_in->sin_port;
        return qtrue;
    }

    case AF_INET6:
    {
        const struct sockaddr_in6 *sadr_in6 = (const struct sockaddr_in6 *)s;
        netadr_ipv6_t *na6 = &address->address.ipv6;

        address->type = NA_IP6;
        memcpy( na6->ip, &sadr_in6->sin6_addr, sizeof( na6->ip ) );
        na6->port = sadr_in6->sin6_port;
        na6->scope_id = sadr_in6->sin6_scope_id;
        return qtrue;
    }

    default:
        NET_SetErrorString( "Unknown address family" );
        return qfalse;
    }
}
Ejemplo n.º 11
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* OpenSocket
*
* returns handle or INVALID_SOCKET for error
*/
static socket_handle_t OpenSocket( socket_type_t type, qboolean ipv6 )
{
    socket_handle_t handle;
    int protocol = ( ipv6 ? PF_INET6 : PF_INET );

    switch( type )
    {
    case SOCKET_UDP:
        handle = socket( protocol, SOCK_DGRAM, IPPROTO_UDP );
        if( handle == INVALID_SOCKET )
        {
            NET_SetErrorStringFromLastError( "socket" );
            return INVALID_SOCKET;
        }
        break;

#ifdef TCP_SUPPORT
    case SOCKET_TCP:
        handle = socket( protocol, SOCK_STREAM, IPPROTO_TCP );
        if( handle == INVALID_SOCKET )
        {
            NET_SetErrorStringFromLastError( "socket" );
            return INVALID_SOCKET;
        }
        else
        {
            struct linger ling;

            ling.l_onoff = 1;
            ling.l_linger = 5;		// 0 for abortive disconnect

            if( setsockopt( handle, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof( ling ) ) < 0 )
            {
                NET_SetErrorStringFromLastError( "socket" );
                return INVALID_SOCKET;
            }
        }
        break;
#endif

    default:
        NET_SetErrorString( "Unknown socket type" );
        return INVALID_SOCKET;
    }

    // Win32's API only defines the IPV6_V6ONLY option since Windows Vista, but fortunately
    // the default value is what we want on Win32 anyway (IPV6_V6ONLY = true)
#ifdef IPV6_V6ONLY
    if( ipv6 )
    {
        int ipv6_only = 1;
        setsockopt( handle, IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&ipv6_only, sizeof( ipv6_only ) );
    }
#endif

    return handle;
}
Ejemplo n.º 12
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_TCP_CheckConnect
*/
static connection_status_t NET_TCP_CheckConnect( socket_t *socket )
{
    struct timeval timeout = { 0, 0 };
    int result;
    fd_set set;

    assert( socket && socket->open && socket->type == SOCKET_TCP );

    if( socket->connected )
        return CONNECTION_SUCCEEDED;

    FD_ZERO( &set );
    FD_SET( socket->handle, &set );

    if( ( result = select( socket->handle + 1, NULL, &set, NULL, &timeout ) ) == SOCKET_ERROR )
    {
        NET_SetErrorStringFromLastError( "select" );
        return CONNECTION_FAILED;
    }
    else if( result )
    {
        struct sockaddr_storage addr;
        socklen_t addr_size;

        if( !FD_ISSET( socket->handle, &set ) )
        {
            NET_SetErrorString( "Write fd not set" );
            return CONNECTION_FAILED;
        }

        // trick to check if we actually got connection succesfully
        // idea from http://cr.yp.to/docs/connect.html
        addr_size = sizeof( addr );
        if( getpeername( socket->handle, (struct sockaddr*)&addr, &addr_size ) != 0 )
        {
            char ch;
            recv( socket->handle, &ch, 1, 0 ); // produces right errno
            NET_SetErrorStringFromLastError( "getpeername" );
            return CONNECTION_FAILED;
        }

        socket->connected = qtrue;

        return CONNECTION_SUCCEEDED;
    }
    else
    {
        return CONNECTION_INPROGRESS;
    }
}
Ejemplo n.º 13
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_Listen
*/
qboolean NET_Listen( const socket_t *socket )
{
    assert( socket->open );

    switch( socket->type )
    {
    case SOCKET_TCP:
        return NET_TCP_Listen( socket );

    case SOCKET_LOOPBACK:
    case SOCKET_UDP:
    default:
        assert( qfalse );
        NET_SetErrorString( "Unsupported socket type" );
        return qfalse;
    }
}
Ejemplo n.º 14
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_Connect
*/
connection_status_t NET_Connect( socket_t *socket, const netadr_t *address )
{
    assert( socket->open && !socket->connected );
    assert( address );

    switch( socket->type )
    {
    case SOCKET_TCP:
        return NET_TCP_Connect( socket, address );

    case SOCKET_LOOPBACK:
    case SOCKET_UDP:
    default:
        assert( qfalse );
        NET_SetErrorString( "Unsupported socket type" );
        return CONNECTION_FAILED;
    }
}
Ejemplo n.º 15
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_SetSocketNoDelay
*/
int NET_SetSocketNoDelay( socket_t *socket, int nodelay )
{
    switch( socket->type )
    {
    case SOCKET_LOOPBACK:
        break;
    case SOCKET_UDP:
        break;
#ifdef TCP_SUPPORT
    case SOCKET_TCP:
        return NET_TCP_SetNoDelay( socket, nodelay );
#endif
    default:
        assert( qfalse );
        NET_SetErrorString( "Unknown socket type" );
        return -1;
    }
    return 0;
}
Ejemplo n.º 16
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_Accept
*/
int NET_Accept( const socket_t *socket, socket_t *newsocket, netadr_t *address )
{
    assert( socket && socket->open );
    assert( newsocket );
    assert( address );

    switch( socket->type )
    {
    case SOCKET_TCP:
        return NET_TCP_Accept( socket, newsocket, address );

    case SOCKET_LOOPBACK:
    case SOCKET_UDP:
    default:
        assert( qfalse );
        NET_SetErrorString( "Unsupported socket type" );
        return qfalse;
    }
}
Ejemplo n.º 17
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_CheckConnect
*/
connection_status_t NET_CheckConnect( socket_t *socket )
{
    assert( socket->open );

    if( socket->connected )
        return CONNECTION_SUCCEEDED;

    switch( socket->type )
    {
    case SOCKET_TCP:
        return NET_TCP_CheckConnect( socket );

    case SOCKET_LOOPBACK:
    case SOCKET_UDP:
    default:
        assert( qfalse );
        NET_SetErrorString( "Unsupported socket type" );
        return CONNECTION_FAILED;
    }
}
Ejemplo n.º 18
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_UDP_GetPacket
*/
static int NET_UDP_GetPacket( const socket_t *socket, netadr_t *address, msg_t *message )
{
    struct sockaddr_storage from;
    socklen_t fromlen;
    int ret;

    assert( socket && socket->open && socket->type == SOCKET_UDP );
    assert( address );
    assert( message );
    assert( message->data );
    assert( message->maxsize > 0 );

    fromlen = sizeof( from );
    ret = recvfrom( socket->handle, (char*)message->data, message->maxsize, 0, (struct sockaddr *)&from, &fromlen );
    if( ret == SOCKET_ERROR )
    {
        net_error_t err;

        NET_SetErrorStringFromLastError( "recvfrom" );

        err = Sys_NET_GetLastError();
        if( err == NET_ERR_WOULDBLOCK || err == NET_ERR_CONNRESET )  // would block
            return 0;

        return -1;
    }

    if( !SockaddressToAddress( (struct sockaddr*)&from, address ) )
        return -1;

    if( ret == (int)message->maxsize )
    {
        NET_SetErrorString( "Oversized packet" );
        return -1;
    }

    message->readcount = 0;
    message->cursize = ret;

    return 1;
}
Ejemplo n.º 19
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_OpenSocket
*/
qboolean NET_OpenSocket( socket_t *socket, socket_type_t type, const netadr_t *address, qboolean server )
{
    assert( !socket->open );
    assert( address );

    switch( type )
    {
    case SOCKET_LOOPBACK:
        return NET_Loopback_OpenSocket( socket, address, server );

#ifdef TCP_SUPPORT
    case SOCKET_TCP:
#endif
    case SOCKET_UDP:
        return NET_IP_OpenSocket( socket, address, type, server );

    default:
        assert( qfalse );
        NET_SetErrorString( "Unknown socket type" );
        return qfalse;
    }
}
Ejemplo n.º 20
0
Archivo: net.c Proyecto: j0ki/racesow
/*
* NET_TCP_Send
*/
static qboolean NET_TCP_Send( const socket_t *socket, const void *data, size_t length )
{
#ifdef USE_TCP_NOSIGPIPE
	int opt_val = 1;
#endif
	int ret;

	assert( socket && socket->open && socket->type == SOCKET_TCP );
	assert( data );
	assert( length > 0 );

#ifdef USE_TCP_NOSIGPIPE
	// Disable SIGPIPE
	// Currently ignore the return code from setsockopt
	setsockopt( socket->handle, SOL_SOCKET, SO_NOSIGPIPE, &opt_val, sizeof( opt_val ) );
#endif

	ret = send( socket->handle, data, length, MSG_NOSIGNAL );

#ifdef USE_TCP_NOSIGPIPE
	// Enable SIGPIPE
	opt_val = 0;
	setsockopt( socket->handle, SOL_SOCKET, SO_NOSIGPIPE, &opt_val, sizeof( opt_val ) );
#endif

	if( ret == SOCKET_ERROR )
	{
		NET_SetErrorStringFromLastError( "send" );
		return qfalse;
	}

	if( ret != (int)length )
	{
		NET_SetErrorString( "Couldn't send all data" );
		return qfalse;
	}

	return qtrue;
}
Ejemplo n.º 21
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* AddressToSockaddress
*/
static qboolean AddressToSockaddress( const netadr_t *address, struct sockaddr_storage *sadr )
{
    assert( address );
    assert( sadr );

    switch( address->type )
    {
    case NA_IP:
    {
        const netadr_ipv4_t *na4 = &address->address.ipv4;
        struct sockaddr_in *sadr_in = (struct sockaddr_in *)sadr;

        memset( sadr_in, 0, sizeof( *sadr_in ) );
        sadr_in->sin_family = AF_INET;
        sadr_in->sin_port = na4->port;
        sadr_in->sin_addr.s_addr = *(int *)&na4->ip;
        return qtrue;
    }

    case NA_IP6:
    {
        const netadr_ipv6_t *na6 = &address->address.ipv6;
        struct sockaddr_in6 *sadr_in6 = (struct sockaddr_in6 *)sadr;

        memset( sadr_in6, 0, sizeof( *sadr_in6 ) );
        sadr_in6->sin6_family = AF_INET6;
        sadr_in6->sin6_port = na6->port;
        sadr_in6->sin6_scope_id = na6->scope_id;
        memcpy( &sadr_in6->sin6_addr, na6->ip, sizeof( sadr_in6->sin6_addr ) );
        return qtrue;
    }

    default:
        NET_SetErrorString( "Unsupported address type" );
        return qfalse;
    }
}
Ejemplo n.º 22
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_IP_OpenSocket
*/
static qboolean NET_IP_OpenSocket( socket_t *sock, const netadr_t *address, socket_type_t socktype, qboolean server )
{
    int newsocket;
    const char *proto, *stype;

    assert( sock && !sock->open );
    assert( address );

    if( address->type == NA_IP )
        proto = "IP";
    else if( address->type == NA_IP6 )
        proto = "IPv6";
    else
    {
        NET_SetErrorString( "Invalid address type" );
        return qfalse;
    }

    if( socktype == SOCKET_UDP )
        stype = "UDP";
#ifdef TCP_SUPPORT
    else if( socktype == SOCKET_TCP )
        stype = "TCP";
#endif
    else
    {
        NET_SetErrorString( "Invalid socket type" );
        return qfalse;
    }

    if( NET_IsAnyAddress( address ) )
    {
        Com_Printf( "Opening %s/%s socket: *:%hu\n", stype, proto, NET_GetAddressPort( address ) );
    }
    else
    {
        Com_Printf( "Opening %s/%s socket: %s\n", stype, proto, NET_AddressToString( address ) );
    }

    if( ( newsocket = OpenSocket( socktype, ( address->type == NA_IP6 ? qtrue : qfalse ) ) ) == INVALID_SOCKET )
        return qfalse;

    // make it non-blocking
    if( !NET_SocketMakeNonBlocking( newsocket ) )
    {
        Sys_NET_SocketClose( newsocket );
        return qfalse;
    }

    if( socktype == SOCKET_UDP )
    {
        // make it broadcast capable
        if( !NET_SocketMakeBroadcastCapable( newsocket ) )
        {
            Sys_NET_SocketClose( newsocket );
            return qfalse;
        }
    }

    // wsw : pb : make it reusable (fast release of port when quit)
    /*if( setsockopt(newsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)) == -1 ) {
    SetErrorStringFromErrno( "setsockopt" );
    return 0;
    }*/

    if( !BindSocket( newsocket, address ) )
    {
        Sys_NET_SocketClose( newsocket );
        return qfalse;
    }

    sock->open = qtrue;
    sock->type = socktype;
    sock->address = *address;
    sock->server = server;
    sock->handle = newsocket;

    return qtrue;
}
Ejemplo n.º 23
0
Archivo: net.c Proyecto: ewirch/qfusion
/*
* NET_TCP_GetPacket
*/
static int NET_TCP_GetPacket( const socket_t *socket, netadr_t *address, msg_t *message )
{
    int ret;
    qbyte buffer[MAX_PACKETLEN + 4];
    int len;

    assert( socket && socket->open && socket->connected && socket->type == SOCKET_TCP );
    assert( address );
    assert( message );

    // peek the message to see if the whole packet is ready
    ret = recv( socket->handle, (char*)buffer, sizeof( buffer ), MSG_PEEK );
    if( ret == SOCKET_ERROR )
    {
        NET_SetErrorStringFromLastError( "recv" );
        if( Sys_NET_GetLastError() == NET_ERR_WOULDBLOCK )  // would block
            return 0;
        return -1;
    }

    if( ret < 4 )  // the length information is not yet received
        return 0;

    memcpy( &len, buffer, 4 );
    len = LittleLong( len );

    if( len > MAX_PACKETLEN || len > (int)message->maxsize )
    {
        NET_SetErrorString( "Oversized packet" );
        return -1;
    }

    if( ret < len + 4 )  // the whole packet is not yet ready
        return 0;

    // ok we have the whole packet ready, get it

    // read the 4 byte header
    ret = NET_TCP_Get( socket, NULL, buffer, 4 );
    if( ret == -1 )
        return -1;
    if( ret != 4 )
    {
        NET_SetErrorString( "Couldn't read the whole packet" );
        return -1;
    }

    ret = NET_TCP_Get( socket, NULL, message->data, len );
    if( ret == SOCKET_ERROR )
        return -1;
    if( ret != (int)len )
    {
        NET_SetErrorString( "Couldn't read the whole packet" );
        return -1;
    }

    *address = socket->remoteAddress;

    message->readcount = 0;
    message->cursize = ret;

    return qtrue;
}