@@ -50,7 +50,7 @@ struct SocketState {
5050 }
5151};
5252
53- UdpSocket::UdpSocket () : IpSocket(), m_state(new (std::nothrow) SocketState), m_recv_port(0 ) {
53+ UdpSocket::UdpSocket () : IpSocket(), m_state(new (std::nothrow) SocketState), m_recv_port(0 ), m_recv_configured( false ) {
5454 FW_ASSERT (m_state != nullptr );
5555}
5656
@@ -67,7 +67,6 @@ SocketIpStatus UdpSocket::configure(const char* const hostname, const U16 port,
6767
6868SocketIpStatus UdpSocket::configureSend (const char * const hostname, const U16 port, const U32 timeout_seconds, const U32 timeout_microseconds) {
6969 // Timeout is for the send, so configure send will work with the base class
70- FW_ASSERT (port != 0 , static_cast <FwAssertArgType>(port)); // Send cannot be on port 0
7170 FW_ASSERT (hostname != nullptr );
7271 return this ->IpSocket ::configure (hostname, port, timeout_seconds, timeout_microseconds);
7372}
@@ -77,6 +76,7 @@ SocketIpStatus UdpSocket::configureRecv(const char* hostname, const U16 port) {
7776 FW_ASSERT (hostname != nullptr );
7877 this ->m_recv_port = port;
7978 (void ) Fw::StringUtils::string_copy (this ->m_recv_hostname , hostname, static_cast <FwSizeType>(SOCKET_MAX_HOSTNAME_SIZE ));
79+ this ->m_recv_configured = true ;
8080 return SOCK_SUCCESS ;
8181}
8282
@@ -112,6 +112,9 @@ SocketIpStatus UdpSocket::bind(const PlatformIntType fd) {
112112 return SOCK_FAILED_TO_READ_BACK_PORT ;
113113 }
114114
115+ // Update m_recv_port with the actual port assigned (for ephemeral port support)
116+ this ->m_recv_port = ntohs (address.sin_port );
117+
115118 FW_ASSERT (sizeof (this ->m_state ->m_addr_recv ) == sizeof (address), static_cast <FwAssertArgType>(sizeof (this ->m_state ->m_addr_recv )), static_cast <FwAssertArgType>(sizeof (address)));
116119 memcpy (&this ->m_state ->m_addr_recv , &address, sizeof (this ->m_state ->m_addr_recv ));
117120
@@ -124,6 +127,7 @@ SocketIpStatus UdpSocket::openProtocol(SocketDescriptor& socketDescriptor) {
124127 struct sockaddr_in address;
125128
126129 U16 port = this ->m_port ;
130+ U16 recv_port = this ->m_recv_port ;
127131
128132 // Acquire a socket, or return error
129133 if ((socketFd = ::socket (AF_INET , SOCK_DGRAM , 0 )) == -1 ) {
@@ -157,11 +161,10 @@ SocketIpStatus UdpSocket::openProtocol(SocketDescriptor& socketDescriptor) {
157161 memcpy (&this ->m_state ->m_addr_send , &address, sizeof (this ->m_state ->m_addr_send ));
158162 }
159163
160- // Receive port set up only done when configure receive was called
161- U16 recv_port = this ->m_recv_port ;
162- if (recv_port != 0 ) {
164+ // Only bind if configureRecv was called (including ephemeral)
165+ if (this ->m_recv_configured ) {
163166 status = this ->bind (socketFd);
164- // When we are setting up for receiving as well, then we must bind to a port
167+
165168 if (status != SOCK_SUCCESS ) {
166169 (void ) ::close (socketFd); // Closing FD as a retry will reopen send side
167170 return status;
@@ -170,22 +173,13 @@ SocketIpStatus UdpSocket::openProtocol(SocketDescriptor& socketDescriptor) {
170173
171174 // Log message for UDP
172175 if ((port == 0 ) && (recv_port > 0 )) {
173- Fw::Logger::log (" Setup to only receive udp at %s:%hu\n " , m_recv_hostname,
174- recv_port);
175- } else if ((port > 0 ) && (recv_port == 0 )) {
176- Fw::Logger::log (" Setup to only send udp at %s:%hu\n " , m_hostname,
177- port);
178- } else if ((port > 0 ) && (recv_port > 0 )) {
179- Fw::Logger::log (" Setup to receive udp at %s:%hu and send to %s:%hu\n " ,
180- m_recv_hostname,
181- recv_port,
182- m_hostname,
183- port);
184- }
185- // Neither configuration method was called
186- else {
187- FW_ASSERT (port > 0 || recv_port > 0 , static_cast <FwAssertArgType>(port), static_cast <FwAssertArgType>(recv_port));
176+ Fw::Logger::log (" Setup to only receive udp at %s:%hu\n " , m_recv_hostname, recv_port);
177+ } else if ((port > 0 ) && (recv_port == 0 )) {
178+ Fw::Logger::log (" Setup to only send udp at %s:%hu\n " , m_hostname, port);
179+ } else if ((port > 0 ) && (recv_port > 0 )) {
180+ Fw::Logger::log (" Setup to receive udp at %s:%hu and send to %s:%hu\n " , m_recv_hostname, recv_port, m_hostname, port);
188181 }
182+
189183 FW_ASSERT (status == SOCK_SUCCESS , static_cast <FwAssertArgType>(status));
190184 socketDescriptor.fd = socketFd;
191185 return status;
@@ -199,7 +193,18 @@ I32 UdpSocket::sendProtocol(const SocketDescriptor& socketDescriptor, const U8*
199193
200194I32 UdpSocket::recvProtocol (const SocketDescriptor& socketDescriptor, U8 * const data, const U32 size) {
201195 FW_ASSERT (this ->m_state ->m_addr_recv .sin_family != 0 ); // Make sure the address was previously setup
202- return static_cast <I32 >(::recvfrom (socketDescriptor.fd , data, size, SOCKET_IP_RECV_FLAGS , nullptr , nullptr ));
196+
197+ struct sockaddr_in sender_addr;
198+ socklen_t sender_addr_len = sizeof (sender_addr);
199+ I32 received = static_cast <I32 >(::recvfrom (socketDescriptor.fd , data, size, SOCKET_IP_RECV_FLAGS ,
200+ reinterpret_cast <struct sockaddr *>(&sender_addr), &sender_addr_len));
201+ // If we have not configured a send port, set it to the source of the last received packet
202+ if (received > 0 && this ->m_state ->m_addr_send .sin_port == 0 ) {
203+ this ->m_state ->m_addr_send = sender_addr;
204+ this ->m_port = ntohs (sender_addr.sin_port );
205+ Fw::Logger::log (" Configured send port to %hu as specified by the last received packet.\n " , this ->m_port );
206+ }
207+ return received;
203208}
204209
205210} // namespace Drv
0 commit comments