This question is similar to https://stackoverflow.com/questions/11650328/using-reliable-multicast-pragmatic-general-multicast-not-returning-from-accept, but my code is slightly different from its, so it may result in a different answer.
I am attempting to get a reliable-multicast server/client proof of concept setup.
The solution itself is a server/client connection. The client connects to the server via TCP/IP. The server then opens up a reliable multicast socket for the client to listen on. The client sends messages via TCP, and the server echoes it back via IPPROTO_RM. The end goal is to have many clients connected to the server, all receiving every echoed message.
The example code is based off of this page.
I have set up my RM sockets similarly (see listings below). The TCP sockets are working fine. The problem is in the RM sockets. The server opens up the multicast socket, then binds and connects to the multicast address properly. The client, however, listens correctly, but the call to accept blocks forever.
Both client and server processes are running on the same host.
I have checked, and Multicasting support is installed on the host (Server 2008).
Update: I've noticed that sometimes the accept will return if I send some data down the socket from the sender's side first. This is not ideal, nor is it reliable.
Update: The signs are pointing to the switch. Seems like a little hub won't cut it. We had an hilarious incident which resulted in lost comms for the whole building.
Listings
Server creates and connects Multicast sender
short
Port = 0;
const char
*Address = "234.5.6.7";
SOCKET
RMSocket;
SOCKADDR_IN
LocalAddr,
SessionAddr;
RMSocket = socket(AF_INET, SOCK_RDM, IPPROTO_RM);
if (RMSocket == INVALID_SOCKET)
{
return Failed;
}
LocalAddr.sin_family = AF_INET;
LocalAddr.sin_port = htons(0);
LocalAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if ( bind( RMSocket, (SOCKADDR*)&LocalAddr, sizeof(LocalAddr)) == SOCKET_ERROR )
{
return Failed;
}
SessionAddr.sin_family = AF_INET;
SessionAddr.sin_port = htons( Port );
SessionAddr.sin_addr.s_addr = inet_addr( Address );
if ( connect( RMSocket, (SOCKADDR*)&SessionAddr, sizeof(SessionAddr)) == SOCKET_ERROR )
{
return Failed;
}
return Success;
Client creates and accepts Multicast reader
short
Port = 0;
const char
*Address = "234.5.6.7";
SOCKADDR_IN
LocalAddr;
SOCKET
RMListener,
RMSocket;
RMListener = socket( AF_INET, SOCK_RDM, IPPROTO_RM );
if ( RMListener == INVALID_SOCKET )
{
return Failed;
}
LocalAddr.sin_family = AF_INET;
LocalAddr.sin_port = htons( Port );
LocalAddr.sin_addr.s_addr = inet_addr( Address );
if ( bind( RMListener, (SOCKADDR*)&LocalAddr, sizeof(LocalAddr) ) )
{
return Failed;
}
if ( listen( RMListener, SOMAXCONN ) )
{
return Failed;
}
// BLOCKS HERE
RMSocket = accept( RMListener, NULL, NULL);
if ( RMSocket == INVALID_SOCKET )
{
return Failed;
}
return Success;
Do you have MSMQ (microsoft message queuing) installed ? it is required for IPPROTO_RM to work on Ms based computers. Plus it will only work for Windows version >= Xp||2003
Edit:I saw that you already checked it.
Related
I am trying to read from a UDP port, from a local (loopback) application, using IOCP. IOCP works fine for TCP/IP, but I am unable to open the socket properly for UDP.
This is what I am doing:
// same as for tcp/ip
struct sockaddr_in remoteAddr = { 0 };
remoteAddr.sin_addr.s_addr = LOOPBACK_ADDRESS;
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_port = htons(portNumber);
// using SOCK_DGRAM here
SOCKET sock = INVALID_SOCKET;
sock = WSASocketW(AF_INET, SOCK_DGRAM, IPPROTO_IP,
NULL, 0, WSA_FLAG_OVERLAPPED);
if( sock == INVALID_SOCKET ) {
LOG("WSASocketW failed: %d", WSAGetLastError());
return;
}
nRet = WSAConnect(*sock, (const struct sockaddr*)&remoteAddr, sizeof(remoteAddr),
NULL, NULL, NULL, NULL);
if (nRet == SOCKET_ERROR)
{
LOG("WSAConnect failed: %d", WSAGetLastError());
return;
}
nRet = WSARecv(sock, &wsabuf, 1, NULL, &flags, &overlapped, NULL);
if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError()))
{
LOG("WSARecv failed: %d", WSAGetLastError());
return;
}
// no errors of any kind
LOG("seems good so far");
Everything passes without errors, but GetQueuedCompletionStatus inside the worker loop thread never returns. If I do the same thing to connect to a TCP socket (just replace SOCK_DGRAM with SOCK_STREAM basically), I get data inside the loop.
Am I doing something obviously wrong?
(Btw) I know I could use WSARecvFrom, but I would like to reuse as much code as possible from the TCP socket. I.e. hopefully, set everything up and then post WSARecv calls inside the worker thread regardless of the type of the socket (WSARecv is supposed to work with UDP properly, AFAIK).
Managed to get it to work, thanks to the comment by #WouterHuysentruit.
Basically, if I want to receive UDP packets using WSARecv, I need to bind. If I want to send UDP packets using WSASend, I need to connect. So the following works:
if (port_type == incoming_packets)
{
// bind to port
ret = bind(*sock, (const struct sockaddr*)&remoteAddr, sizeof(remoteAddr));
...
WSARecv(...);
}
else
{
// this can send to a loopback udp port which is bound in
// a different application
ret = WSAConnect(*sock, (const struct sockaddr*)&remoteAddr, sizeof(remoteAddr), ...);
...
WSASend(...);
}
As others have pointed out, WSAReceiveFrom/WSASendTo are usually a better choice for UDP, but in this case I can support multiple port types using IOCP transparently.
Our software had problems connecting to a SIEMENS PLC. We created a socket and continually did connect() on it, always receiveing WSAETIMEDOUT. Telnetting to the PLC on the exact same IP and port worked. Pseudocode below:
// Does not work
SOCKET reconnect(char* ip) {
SOCKET sock = socket(PF_INET,SOCK_STREAM,0);
struct sockaddr_in addr = make_addr();
int err;
while(1) {
err = connect(sock,(struct sockaddr FAR*) &addr,sizeof(addr));
if( err==SOCKET_ERROR ) {
log() // WSAETIMEDOUT logged here
continue;
}
return sock;
}
}
After changing the code to create a new socket for each connect() call, it seems to work...
// Works
SOCKET reconnect(char* ip) {
struct sockaddr_in addr = make_addr();
int err;
while(1) {
SOCKET sock = socket(PF_INET,SOCK_STREAM,0);
err = connect(sock,(struct sockaddr FAR*) &addr,sizeof(addr));
if( err==SOCKET_ERROR ) {
log() // WSAETIMEDOUT logged here
closesocket(sock);
continue;
}
return sock;
}
}
The first snippet has been running successfully in production for ~20 years, across multiple versions of Windows. I suspect it doesn't follow the specs though... Has there been any changes/updates to Windows Server 2012 R2 (which is what the customer is running) that changes this behavior?
EDIT
According to the docs,
If the error code returned indicates the connection attempt failed
(that is, WSAECONNREFUSED, WSAENETUNREACH, WSAETIMEDOUT) the
application can call connect again for the same socket.
... which makes this even more puzzling.
Your code was always wrong. A failed connect() always hoses the socket. You were lucky it worked so long.
Rewritten to try and be clear on what I need.
My goal is to duplicate the function of a device made by Digital Yacht in an embedded Intel Edison processor running C and Linux. The device sends via UDP to phone apps such as iRegatta and others. To set up the app, only the port number is entered. No ip address is entered in UDP mode on the app. I thought this was trivial but the experts here so far have said it is impossible so it must not be trivial. Perhaps that is why with all my hours of reading I cannot find an example. I am being voted down because, I am told, that what I am trying to do it impossible but it is not as it is done. I don't know how it is done, which is why I came to experts here.
I want to send nmea messages that might look like this:
$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
and I want any number of random Android phones to be able to receive them with the appropriate app. There are many apps that can be set up to receive UDP data where you just specify a port number. There is no ip address involved in the setup of the apps. Also, I do not wish to receive anything from the Android phones. This is one way and no ability to re-transmit so if a message does not get there, it has another chance next time. Everything is updated once a second.
I tried the following and I do not get data in the app. From the comments, I must need to add some kind of router function in my Linux machine.
void init_udp(){
return;
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0){
printf("ER UDP Socket error\n");
}
else printf("UP Socket %d OK\n",sock);
}
void write_udp(char *buf){
return;
// nmea data is in buff
if (sock >= 0){
int on = 1;
setsockopt( sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on) );
struct sockaddr_in address = {0};
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr( "255.255.255.255" ); //
address.sin_port = htons( 3000 );
if ( sendto( sock, buf, strlen(buf), 0, (struct sockaddr*)&address, sizeof(address) ) < 0) printf("ER UDP send error\n");
else {
printf("UP %s\n",buf);
}
}
}
I am not really sure what I need to do.
What you want to do is send a UDP packet to a broadcast IP address. This will send to thing in the subnet.
eg 10.255.255.255 is the broadcast address for the 10.x.x.x subnet. You can also use the global 255.255.255.255 which should also send to your subnet and no router is going to pass that on to another one these days.
Also you need to make your socket able to send broadcast messages. In particular you need the option SO_BROADCAST set. The following is specifically Windows because of the BOOL. Its presumably an int for most platforms.
BOOL on = TRUE;
setsockopt( sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on) );
Also you can't use send() for a UDP socket unless its "connected", so you should use sendto() and use the broadcast address.
To specify an address and port, use need to create a socket address.
struct sockaddr_in address = {0};
address.sin_family = AF_INET;
address.sin_add.s_addr = inet_addr( "255.255.255.255" );
address.sin_port = htons( 3000 );
sendto( sock, buff, strlen(buff), 0, (struct sockaddr*)&address, sizeof(address) );
Note the use of the typecast. This is because sendto takes a sockaddr which is a generic address type, and here we are using an IPV4 address specifically. The sockaddr_in maps onto the sockaddr
int udp_sock() {
//Create socket
sock = socket(AF_INET , SOCK_DGRAM , 0);
if (sock == -1) {
printf("Could not create socket\n");
}
puts("Socket created.......\n");
server1.sin_addr.s_addr = inet_addr("172.210.110.10");
server1.sin_family = AF_INET;
server1.sin_port = htons(PORT);
//Connect to remote server
con= connect(sock , (struct sockaddr *)&server1 , sizeof(server1));
if(con<0) {
perror("connect failed. Error\n");
return con;
}
puts("Connected\n");
return 0;
}
The packet is reaching server mentioned, but the error "destination port unreachable" comes up in Wireshark.
How to assign a UDP port on my client to receive data on a particular port?
How to assign two different ports - 1024 and 1025 to receive data?
Any suggestions will be helpful.
There needs to be a server waiting on the other end. A simple way for testing is to use netcat.
nc -lu 8053
Alternatively set up a utility that is designed for udp testing, such as echo server. This is normally built into an inetd or xinetd server
If you want to intercept incoming udp packets you will need to use bind() select()/poll()/epoll() and recvfrom()
I am writing UDP server and client in C on UNIX. I need to handle each client in its own thread on server. In each thread, I want to receive only messages from corresponding client. Right now I am peeking messages using recvfrom and checking message whether it is "mine".
I heard that it is possible to have multiple sockets listening on the same host:port and connect each of them to corresponding client so it will receive messages only from the said client. Here is the code I run when I run into new client. However, after first client connects messages are in fact filtered, but not only on new socket, but also on main socket listening for new clients, so I cant connect new clients.
void fun(int* sockfd, struct sockaddr_in* my_addr, struct sockaddr_in* cli_addr)){
if ((*sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
ERR("socket");
}
int optval = 1;
bzero(my_addr, sizeof (*my_addr));
my_addr->sin_family = AF_INET;
my_addr->sin_port = htons(PORT);
my_addr->sin_addr.s_addr = htonl(INADDR_ANY);
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)) < 0) {
ERR("setsockopt");
}
if (bind(sockfd, (struct sockaddr*) my_addr, sizeof (*my_addr)) == -1) {
ERR("bind");
}
if (connect(*socket, (struct sockaddr*) cli_addr, sizeof (*cli_addr)) < 0)
ERR("connect");
}
}
Is there a better (and working) way to filter UDP messages?
In my opinion you should use one thread for receiving and sending data and then dispatch to the other threads.
There is no need for more than one socket server side. One socket receive all datagrams, you process them by extracting the source, and then dispatch it.
You could do something like this:
Datagram is read:
source is known, call the backback you have for it
source is not known, create a new thread, and register a callback for this source.
Whenever you want to "disconnect" a client, unregister the callback and remove the thread.
Note that by "disconnect" I mean in a logical way for your application, since UDP socket are not connected.