two way UDP com with non max objects

yair reshef's icon

this is a followup to a thread on the dev board > https://cycling74.com/forums/udp-sendrecieve-to-non-max-objects

im still having problems with ports and non max UDP comm

when i use processing (OSCp5 lib) OSCarguments example http://i.imgur.com/8Ijui.png (code pic)

i get this (via packet sniffer wireshark)
http://i.imgur.com/2ufqs.png (wireshark capture)
here i set a "receive" on port 6000, and a "send" on port 5656

in arduino (+ethrent shield) i set receive to port 5656 and
send port to be auto assigned via
`
// send a reply, to the IP address and port that sent us the packet we received
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
http://i.imgur.com/of1td.png (full code)

on max my udpsend src port is always different, it sends but max will not receive data
http://i.imgur.com/6sod8.png (wireshark capture)

cant i set the destination port explicitly?
how can i bind udpreceive to that auto-generated port?
[udpsend 10.0.0.55 5656]
even when exclipctly targeting a port i dont get anything.

i tried mxj net.udp.send, sadam.udpSender object. all with same outcome.

windows x64, max6.04

$Adam's icon

Hi,

two-way UDP (or TCP) communication is a bit harder, as normally you need to let the socket open during the entire transaction. Max objects that do networking (udpsend/receive, mxj net stuff and my sadam.* objects) won't do that for you, as they all (1) open a socket, (2) send the data and then (3) close the socket. I'm developing a TCP object that would let the socket open (therefore, which would do two-way communication), but I can't tell when it would be ready. If you know a little bit of C, the easiest way would be to do a simple two way external for the actual purpose, or wait for a general-purpose tool.

HTH,
Ádám

yair reshef's icon

first thanks for your objects, and especialy for cross compiling to windows. a hassle and i apprciate that
as for twoway, i will find something, If you have some snippets for that c part i would love to take a look

$Adam's icon

Hi,

well, the best thing you can do in this case is a google lookup for standard Server-Client code snippets for Windows. However, before doing so, you have to think a little bit about your network setup. As in each two-way network scenario, there must be a server (which runs during all the time in the background and for each incoming requests it starts a new thread for managing the communication) and a client (which would initiate and terminate the communication with the server in the proper way). So, the first thing is, you need to know who is the 'server' and who is the 'client' in your case (unfortunately I don't know neither Processing nor Arduino, so I've no idea of how networking works there). If you're lucky, then they would act as servers, in which case you don't need to take care of the server tasks in Max, you'd just need to implement a simple client.

Here's the code that I'm using in [sadam.udpSender]. Feel free to use it and extend it according to your needs. This is not a trivial task, however - you'd need to understand what you're doing anyway.

The ERR_* macros are just error messages that I define earlier, you can ignore them. The rest of the definitions are in the header files that you need to include (in the WIN_VERSION and MAC_VERSION blocks):

#ifdef WIN_VERSION
#include 
#endif

#include 
#include 
#include 
#include 
#include "ext.h"
#include "ext_obex.h"
#include "ext_globalsymbol.h"
#include "ext_systhread.h"
#include "sadam.stream.h"

#ifdef MAC_VERSION
#include 
#include 
#include 
#include 
#endif

And here is the function that actually sends the data:

void UDPSender::sendData ( std::vector < unsigned char > & data ) {
    struct sockaddr_in localAddress;
    struct sockaddr_in serverAddress;
    struct hostent *   hPrt;
    t_symbol *         localHost;
    unsigned char *    buffer;
    unsigned char *    iterator;
    unsigned long      localPort;
    unsigned long      size;
    long               result;
#ifdef WIN_VERSION
    SOCKET  socketDescriptor;
    WSADATA wsaData;
#else
    int socketDescriptor;
#endif

    if ( data.empty ( ) ) {
        return;
    }
    localHost = host;
    localPort = port;
    // Create socket
#ifdef WIN_VERSION
    if ( ( result = WSAStartup ( MAKEWORD(1, 1), & wsaData ) ) != 0 ) {
        if ( verbose ) {
            object_error ( ( t_object * ) this, ERR_WSA );
        }
        outlet_int ( outlet, result );
        return;
    }
    socketDescriptor = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
    if ( socketDescriptor == INVALID_SOCKET ) {
        WSACleanup();
#else
        socketDescriptor = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
        if ( socketDescriptor < 0 ) {
#endif
            if ( verbose ) {
                object_error ( ( t_object * ) this, ERR_SOCKET, localHost->s_name );
            }
            outlet_int ( outlet, errno );
            return;
        }
        // Bind port
        localAddress.sin_family = AF_INET;
        localAddress.sin_addr.s_addr = htonl ( INADDR_ANY );
        localAddress.sin_port = htons ( 0 );
        if ( bind ( socketDescriptor, ( struct sockaddr * ) & localAddress, sizeof ( localAddress ) ) != 0 ) {
            if ( verbose ) {
                object_error ( ( t_object * ) this, ERR_BIND, localPort, localHost->s_name );
            }
            outlet_int ( outlet, errno );
#ifdef WIN_VERSION
            closesocket ( socketDescriptor );
            WSACleanup();
#else
            close ( socketDescriptor );
#endif
            return;
        }
        // Get server address
        hPrt = gethostbyname ( localHost->s_name );
        if ( hPrt == NULL ) {
            result = -1;
            if ( verbose ) {
                object_error ( ( t_object * ) this, ERR_HOST, localHost->s_name );
            }
            outlet_int ( outlet, result );
            return;
        }
        serverAddress.sin_family = hPrt->h_addrtype;
        memcpy ( ( char * ) & serverAddress.sin_addr.s_addr, hPrt->h_addr_list [ 0 ], hPrt->h_length );
        serverAddress.sin_port = htons ( localPort );
        // Send data
        size = data.size ( );
        buffer = new unsigned char [ size ];
        iterator = buffer;
        for ( std::vector < unsigned char >::iterator i = data.begin ( ); i != data.end ( ); ++ i ) {
            * iterator ++ = * i;
        }
        iterator = buffer;
        result = sendto ( socketDescriptor, ( const char * ) iterator, size, 0, ( const struct sockaddr * ) & serverAddress, sizeof ( serverAddress ) );
        if ( result < 0 ) {
            if ( verbose ) {
                object_error ( ( t_object * ) this, ERR_SEND, host->s_name, localPort );
            }
            outlet_int ( outlet, result );
        }
        delete [ ] buffer;
        outlet_int ( outlet, 0 );
#ifdef WIN_VERSION
        closesocket ( socketDescriptor );
        WSACleanup();
#else
        close ( socketDescriptor );
#endif

    }

}

Hope this helps,
Ádám

yair reshef's icon

thanks for the indepth

EDIT:
note to self, if packet sniffer acknowledged shipped packet,
and you still don't get anything in max, *check your FIRWALL*

all is well, two way comm is working,
wish all my problems could be solved with a toggle

[shamE shaME shAME sHAME SHAME]