UDP datagram set source port

OK, I went a bit crazy before I realised this is what was happening. I need to set the source port of my UDP message as the unit I am communicating with uses the source port as the port it replies to.

It seemed easier to use ofxPocoNetwork to make these changes as there was less code so I added this method.

int UDPClient::sendMessageTo(ofBuffer& buffer, int port) {
        if(connected) {
            //here is the line I changed
            int sendTo(const void* buffer, int length, const SocketAddress& address, int flags = 0);
            try {
                socketAddress = new Poco::Net::SocketAddress(sendIpAddress, port);
                int sent = socket->sendTo(buffer.getData(), buffer.size(), *socketAddress);
                //int sent = socket->sendTo(buffer, sendSize, *socketAddress);
                return sent;
            } catch (Poco::Exception &e) {
                ofLogError() << "* UDPClient send fail 1";
                return 0;
            } catch(std::exception& exc) {
                ofLogError() << "* UDPClient send fail 2";
                return 0;;
            } catch (...) {
                ofLogError() << "* UDPClient send fail 3";
                return 0;
            }
        }
        return 0;
    }

But I think that is the wrong approach and I need to set the address of the datagram here in the connect method

void UDPClient::connect(string ipAddr, int port) {

    // setup tcp poco client
    socketAddress = new Poco::Net::SocketAddress(ipAddr, port);
    socket = new Poco::Net::DatagramSocket(Poco::Net::IPAddress::IPv4);
    sendIpAddress =ipAddr;
    
    try {
        
        // client must connect to server
        socket->connect(*socketAddress);
        connected = true;
        ofLog() << "UDPClient connected";
        ofLog() << "Max receive size: " << socket->getReceiveBufferSize();
        ofLog() << "Max send size: " << socket->getSendBufferSize(); // 9216
        
        
    } catch (Poco::Exception& exc) {
        
        disconnect();        
        ofLog() << "UDPClient Error: could not create socket- " << exc.displayText();
    }
}

I got some info from stack overflow here

This seems to imply I need to change the socket initialisation here

void UDPClient::connect(string ipAddr, int port) {

    // setup tcp poco client
    socketAddress = new Poco::Net::SocketAddress(ipAddr, port);
    socket = new Poco::Net::DatagramSocket(Poco::Net::IPAddress::IPv4);

But I really don’t understand how I can do that - I messed with it for a few hours but the syntax is over my head.

If anyone knows how to add this functionality I would really appreciate it, or if there is another simple library that someone has an addon for that would be also great.

maybe
@trentbrooks knows as that is where this addon came from.

Cheers

Fred

Ok, I think this is the solution, adding this method in the UDPClient from ofxPocoNetworking

void UDPClient::connect(string ipAddr, int port, int sourcePort) {

    // setup tcp poco client
    socketAddressSource = new Poco::Net::SocketAddress(ipAddr, sourcePort);
    socketAddress = new Poco::Net::SocketAddress(ipAddr, port);
    socket = new Poco::Net::DatagramSocket(*socketAddressSource);
   
    
    try {
        
        // client must connect to server
        socket->connect(*socketAddress);
        connected = true;
        ofLog() << "UDPClient connected";
        ofLog() << "Max receive size: " << socket->getReceiveBufferSize();
        ofLog() << "Max send size: " << socket->getSendBufferSize(); // 9216
        
        
    } catch (Poco::Exception& exc) {
        
        disconnect();        
        ofLog() << "UDPClient Error: could not create socket- " << exc.displayText();
    }
}

I don’t have access to the device but when I monitor the transfers with this method using wireshark I do see the source port stays, however, the protocol now says LLC as opposed to UDP. However I think this

https://www.wireshark.org/lists/wireshark-users/200701/msg00227.html

implies that it is all fine.

Unless anyone knows better - please let me know if this looks suspect or dodgy.

Fred

Hey @fresla,

I see you solved this - nice work. I had only implemented a very basic UDP example in the addon (client only sends, server only receives). The updates you made will allow the client to receive as well- I will try update the addon based on your code when I have time. Thanks!

Also their is a 2nd optional parameter ‘reuseAddress’ for the DatagramSocket constructor which should probably be set to true in your case? https://github.com/pocoproject/sandbox/blob/master/Sockets/src/DatagramSocket.cpp#L60

Trent

Ok, this worked for my tests inside local host but not in the real world. I could specify the source port but of course the port was then taken and my second object, a udpServer could not take the port to receive incoming messages. I need to combine the client and the server starting with the above code so I got this frankenclass so far.

    #pragma once

#include "ofMain.h"
#include "ofMain.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"

/*
 UDPClient
 - poco based udp: http://pocoproject.org/docs/Poco.Net.DatagramSocket.html
 - wip
 - sender only
 
 TODO: add receiving + threading maybe?
 */

namespace ofxPocoNetwork {

class UDPClient : public ofThread  {
public:
    
    UDPClient();
    virtual ~UDPClient();
    void disconnect();
    
    void connect(string ipAddr, int port,int sourcePort);
    bool connected;
    
    // send (blocking)
    int sendMessage(string msg);
    int sendMessage(ofBuffer& msg);
    
    // advanced- internal poco buffer sizes (best not to change this unless you need video or something)
    void setMaxSendSize(int size); // change pocos max send size- default 9216
    int getMaxSendSize();
    int getDatagramSourcePort();
    
    void threadedFunction();
    
    // receive
    bool hasWaitingMessages();
    int parseMessage();
    void setReceiveSize(int size);
    
    // send
    bool getNextMessage(ofBuffer& message);
    bool getNextMessage(string& msg);
    
    bool getNextMessage(uint8_t msg[]);
    
protected:
    int sleepTime;
    int receiveSize;
    
    bool waitingRequest; // temp var applied to any connection

    Poco::Net::SocketAddress* socketAddress;
    Poco::Net::SocketAddress* socketAddressSource;
    Poco::Net::DatagramSocket* socket;
    
    int maxBufferSendSize;
    queue<ofBuffer> receiveBuffers;

};

} // namespace ofxPocoNetwork

and the cpp file

indent preformatted text by 4 spaces   msg = receiveBuffers.front().getData();
            receiveBuffers.pop();
            return true;
        }
        return false;
    }
// advanced- internal poco buffer sizes
//--------------------------------------------------------------
void UDPClient::setMaxSendSize(int size) {
    if(connected) {
        
        // advanced: change pocos max internal buffer send size- default send is 9216
        socket->setSendBufferSize(size);
        ofLog() << "Max send size: " << socket->getSendBufferSize();
    }
}

int UDPClient::getMaxSendSize() {
    if(connected) {
        return socket->getSendBufferSize();
    }
    return 0;
}

} // namespace ofxPocoNetwork

But of course it is not working… if anyone has any hints on how to do this ti would be great. It seems it is a very common routine.

Hey, that cpp file is cutoff. Do you want to email me or private message to continue the conversation - and we will post back when it’s solved. Thanks.

So it seems to be working fine- I have tested it extensively with wireshark and for the moment I can get bi-directional communication with the port.

I made a fork of ofxPocoNetwork here

There are still somethings to fix, especially the size in the receive from method seems to be inaccurate.

If anyone else needs this go for it- the structure of the ofxUdpManager inside OF implies it can also achieve this (you can connect and bind with the same object) but it resets the client source port as soon as it receives its first message.

Fred