Diversos problemas con mod_fsock y conexiones UDP

Started by darío, June 20, 2016, 01:49:04 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

darío

Llevo un par de días intentando entender cómo hacer funcionar mod_fsock para conexiones UDP de un modo correcto y tengo varios problemas. Todos los ejemplos que he visto de uso de la mod_fsock hacen uso de TCP y he intentado leer todo lo posible tanto en la web, como en un "leeme.txt" que acompaña a la mod_fsock así como el propio código de la mod_fsock.

Estoy usando Linux y compilando con PixTudio.

1. El tema del bloqueo (fsock_setblock) que consido solucionar si modifico libsocket.c como ya he expuesto en mi tema anterior.

2. udpsock_recv devuelve siempre -1. Leyendo el código de libsocket.c entiendo que en Linux el valor devuelto se corresponde con recvfrom. En teoría un valor de -1 indicaría que ha habido algún problema, pero sin embargo los datos si que parecen ser recibidos!

3. No entiendo el valor devuelto por udpsock_recv en los dos últimos parámetros:


    char bytes[0];
    unsigned short port;
    unsigned int ip_address;



            received_bytes = udpsock_recv ( socket,
                &bytes,
                1,
                &ip_address,
                &port );


Entiendo que esto viene de:

int libsocket_recv_udp(int socket, void *dest, size_t len, int *ip, int *port) {
    struct sockaddr_in connection_info;
    int received_bytes;
#ifdef WIN32
    int connection_info_size;
#else
    unsigned int connection_info_size;
#endif

    received_bytes =
        recvfrom(socket, dest, len, 0, (SOCKADDR *)&connection_info, &connection_info_size);

    if (socket != -1) {
        *ip   = connection_info.sin_addr.s_addr; // ip
        *port = ntohs(connection_info.sin_port); // puerto
    }

    return received_bytes;
}


Pero no entiendo por qué siempre recibo una dirección IP que no tiene nada que ver con ninguna de las IPs de mi ordenador, ni el puerto tiene nada que ver con el puerto que he habilitado para establecer la comunicación.

Adjunto un video donde se muestra tanto el problema #2 como el problema #3. La ventana de consola de arriba a la derecha es una sesión en una raspberry local que tengo en mi red, y como véis, la información enviada por UDP es correctamente recibida en mi juego. La ventana de abajo a la derecha es un programa en Mono corriendo localmente, y también cuando envío un byte por ahí lo recibo en mi juego, pero no entiendo la IP que se muestra ni tampoco el puerto que se muestra, ya que en teoría yo estoy trabajando sobre el puerto 11000.

Mi código, después de un fsock_init:


Const
    _MULTIPLAYER_RECEIVE_INTERVAL = 300; // 1/100 s
    _MULTIPLAYER_TIMER_RECEIVE = 0;
End
Process multiplayer_receiver ()
Private
    int socket;
   
    char bytes[0];
    unsigned short port;
    unsigned int ip_address;
   
    int received_bytes;
    int n;
    string ip_text;
End
Begin
    socket = udpsock_open ();
    //say ( "Result setblock: " + fsock_setblock ( socket, 0 ) );
    fsock_bind ( socket, 11000 );
     
    timer [ _MULTIPLAYER_TIMER_RECEIVE ] = 0;
   
    Loop
        If ( timer[ _MULTIPLAYER_TIMER_RECEIVE ]
                > _MULTIPLAYER_RECEIVE_INTERVAL )
           
            ip_text = "";
            received_bytes = 0;
            bytes[0] = 0;
            port = 0;
            ip_address = 0;
           
            received_bytes = udpsock_recv ( socket,
                &bytes,
                1,
                &ip_address,
                &port );
           
            say ( "Received: " + received_bytes );
            say ( "Address: ");
            From n=0 To 3;
                ip_text += itoa( ( ip_address & (255 << n * 8) ) >> ( n * 8 ) ) + ".";
            End
            say ( "IP: " + ip_text );
            say ( "Port: " + port );
            say ( "Byte 0: " + bytes[0]);
           
            If ( received_bytes > 0 )
                // multiplayer_process_receive_frame ( &bytes );
            End
           
            say ("");
           
            timer[ _MULTIPLAYER_TIMER_RECEIVE ] = 0;
        End
       
        Frame;
    End

OnExit:
    fsock_close(socket);
End


A ver si alguien me puede echar una mano... Muchas gracias...
My sites:
Smart Fpg Editor - Painless FPG Edition for Bennu and PixTudio
fenixlib - .NET support for manipulating PixTudio, Bennu and Div graphic formats

panreyes

Lo de la IP que no corresponde, lo desconozco. ¿Es posible que esté invertida?

Por otro lado, quizás lo del puerto esté relacionado con que sea el puerto de salida. El puerto de entrada tiene que ser el 11000, pero el de salida puede ser cualquiera aleatorio.

darío

No, eso ya lo había pensado, pero no está invertida. En cualquier caso creo que la función no debería devolver -1. Voy a ver si puedo investigar más... Estoy leyendo la documentación de recvfrom, pero parece que puede depender de la plataforma...

Lo del puerto, reconozco que no tengo mucha experiencia con conexiones sockets, para que sirve que dicha función devuelva el "puerto de salida"?
My sites:
Smart Fpg Editor - Painless FPG Edition for Bennu and PixTudio
fenixlib - .NET support for manipulating PixTudio, Bennu and Div graphic formats

darío

He probado a hacer un say() de fsock_errno y devuelve 22.

De acuerdo a http://www.virtsync.com/c-error-codes-include-errno significa EINVAL.

He visto también que con mi fix para fsock_setblock, recibo un 11 cuando no envío ningún paquete, que significa EWOULDBLOCK = EAGAIN, y de acuerdo a la documentación de recvfrom es correcto.

Sigo investigando...
My sites:
Smart Fpg Editor - Painless FPG Edition for Bennu and PixTudio
fenixlib - .NET support for manipulating PixTudio, Bennu and Div graphic formats

darío

He encontrado el bug!

De acuerdo con http://stackoverflow.com/questions/2999639/recvfrom-returns-invalid-argument-when-from-is-passed, el parámetro connection_info_size de recvfrom tiene que ser inicializado a size_of (connection_info)!

Haciendo esto el programa funciona sin problemas!

Ahora haré un pull-request al repo de PixStuio para que lo podáis probar.

:)

My sites:
Smart Fpg Editor - Painless FPG Edition for Bennu and PixTudio
fenixlib - .NET support for manipulating PixTudio, Bennu and Div graphic formats

darío

Notese que el mismo problema aplica  a BennuGd...
My sites:
Smart Fpg Editor - Painless FPG Edition for Bennu and PixTudio
fenixlib - .NET support for manipulating PixTudio, Bennu and Div graphic formats

darío

La única linea cambiada es la de connection_info_size, que ahora se inizializa a sizeof(connection_info).


int libsocket_recv_udp(int socket, void *dest, size_t len, int *ip, int *port) {
    struct sockaddr_in connection_info;
    int received_bytes;
#ifdef WIN32
    int connection_info_size;
#else
    unsigned int connection_info_size = sizeof(connection_info);
#endif

    received_bytes =
        recvfrom(socket, dest, len, 0, (SOCKADDR *)&connection_info, &connection_info_size);

    if (socket != -1) {
        *ip   = connection_info.sin_addr.s_addr; // ip
        *port = ntohs(connection_info.sin_port); // puerto
    }

    return received_bytes;
}

My sites:
Smart Fpg Editor - Painless FPG Edition for Bennu and PixTudio
fenixlib - .NET support for manipulating PixTudio, Bennu and Div graphic formats

josebita

Mil gracias, darío :)
Tu cambio ya está en el repositorio de PixTudio.

darío

Yeahh después de todo el día investigando esto ahora sí que me siento realizado!

8)
My sites:
Smart Fpg Editor - Painless FPG Edition for Bennu and PixTudio
fenixlib - .NET support for manipulating PixTudio, Bennu and Div graphic formats