Socket transmit data but can't receive response - c++

I am trying to implement UpNP in C++, I found a few sources on google but none worked. I found this one working (http://www.codeproject.com/KB/IP/upnplib.aspx) but it's for .NET, so I decided to sniff the network to see what the code was doing and then do the same with sockets.
Here are the results (full size: http://i.stack.imgur.com/eLoHK.jpg):
That shows me that the packet doesn't look bad, everything seems to be the same, everything but the source address of my code, which I don't know how to control (both my code and finder.net.exe are being tested on the same computer connected to the same network).
Here's my code:
#define upnp_broadcast_ip "239.255.255.250"
#define upnp_broadcast_port 1900
#define upnp_search_request "M-SEARCH * HTTP/1.1\r\n" \
"Host:239.255.255.250:1900\r\n" \
"ST:upnp:rootdevice\r\n" \
"Man:\"ssdp:discover\"\r\n" \
"MX:3\r\n" \
"\r\n"
WSAStartup(MAKEWORD(2, 2), &WsaData);
BOOL discover( )
{
SOCKET ConnectSocket;
struct sockaddr_in Addr;
char Buffer[1450];
int t = 0,
iResult = 0,
TrueLen = sizeof(bool);
bool True = true;
ulong One = 1;
// Open datagram socket
ConnectSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
// Clear out struct
memset( &Addr, 0, sizeof(Addr) );
// Specify the address family, IP address, and port
Addr.sin_family = AF_INET;
Addr.sin_port = htons( upnp_broadcast_port );
Addr.sin_addr.s_addr = inet_addr( upnp_broadcast_ip );
iResult = setsockopt( ConnectSocket, SOL_SOCKET, SO_BROADCAST, (char*)&True, TrueLen ); // Not sure what is this for
// Transmit data
int sent = sendto( ConnectSocket, upnp_search_request, strlen(upnp_search_request), 0, (struct sockaddr*)&Addr, sizeof(Addr) );
// Try to receive data 10 times
for( t = 0; t < 10; t++ )
{
ioctlsocket( ConnectSocket, FIONBIO, &One );
// Clear out buffer
memset( &Buffer, 0, sizeof(Buffer) );
int length = sizeof(Addr);
// Receive data
iResult = recvfrom( ConnectSocket, Buffer, (sizeof(Buffer) - 1), 0, (struct sockaddr*)&Addr, &length );
if( iResult == SOCKET_ERROR)
{
Sleep( 1000 );
continue;
} else {
// Do stuff with received data
}
}
closesocket( ConnectSocket );
return FALSE;
}
I removed all the WSAGetLastError() error checking to make the code easier to read, everything goes fine until recvfrom, that always returns -1 and strerror(WSAGetLastError()) prints "Unknown error".
I hope someone could guide me in the right direction, I've been the last two days trying to make this work.

Why broadcast? UPnP uses multicast, so as far as I remember (Unix) you should use setsockopt() to request that the kernel join a multicast group. I am not sure about Windows, it could be the same call.
Something like:
struct ip_mreq mreq;
....
mreq.imr_multiaddr.s_addr=inet_addr(GROUP_IP);
mreq.imr_interface.s_addr=htonl(INADDR_ANY);
setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))

EDIT:
As hasturkun pointed out, my initial answer was wrong. Also, slemdx correctly diagnosed the problem: the uPnP request is going out from the wrong interface. The problem is, I am not sure how you can determine the right interface. One possibility is to use the interface containing the default gateway on the routing table, but I don't think that would be the right choice. There may be uPnP devices hooked to other interfaces.
One option is to send the initial search packet on all available interfaces. Maybe the answers to this question can help. There is also another link on the last answer that you should check out.

Related

How to receive multicast UDP packets correctly?

new to multicast networking, I need to receive UDP packets from a multicast channel through one of the NICs on my windows box, followed Microsoft docs and some blog entry, but still having issues.
I create a socket via
ls = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
call.
Then setsockopt to SO_REUSEADDR
unsigned int reuse = 1;
if( setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0 )
{
LOG4CXX_ERROR(logger, "Reusing ADDR failed. Err: " << WSAGetLastError());
}
If socket is good
int result = bind(ls, reinterpret_cast<SOCKADDR*>(&server), sizeof(server));
where
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(myport);
If bind succedes
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("e.f.g.h");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if( setsockopt(ls, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) < 0 )
{
LOG4CXX_ERROR(logger, "setsockopt multicast group add membership failed. Err: " << WSAGetLastError());
}
The box on which I need to receive packets has four NICs, network administrators told me that I have to use the third one, let's say that it has a.b.c.d IPv4 address
They told me also that mcast IP is e.f.g.h
If I run windump.exe -i 3 on my windows box I see something like this
... 12:53:58.454987 IP i.k.l.m.xxxxx > e.f.g.h.myport: UDP, length 58
...
After initializing my UDP socket I call recvfrom
sz = recvfrom(ls, buffer, DATA_BLOCK_SIZE, 0, reinterpret_cast<SOCKADDR*>(&client), &size);
where sz is an int, ls is my socket, buffer is a "suitable buffer", DATA_BLOCK_SIZE is buffer size, client is a SOCKADDR pointer to receive info from the sender, and size is the received message size.
My code stucks in the recvfrom call never receiving anything.
I'm clearly making a mistake somewhere but not understanding where and worse why.
If someone can explain me what's happening it will be very appreciated.
SOLVED ...
I changed these lines only
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("e.f.g.h");
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
to
struct ip_mreq mreq;
inet_pton(AF_INET, "e.f.g.h", &(mreq.imr_multiaddr));
inet_pton(AF_INET, "a.b.c.d", &(mreq.imr_interface));
As I have guessed I was not correctly indicating in my struct ip_mreq which was the network interface to use for multicast messages.
It was my fault. Sorry for the noise.

UDP server connecting and sending data weirdness

I am making async (well non-blocking rly) sockets lib for educational purposes. TCP part works just fine, but when it comes to UDP i experience weird behavior. Following code works as expected - server receives data:
MyUDPSocket server;
server.Bind(5551);
MyUDPSocket client;
client.Connect("192.168.0.103", 5551);
Sleep(10);
client.Write("\x0", 1);
Sleep(10);
client.Write("test", 5);
But if either of Sleep() or client.Write("\x0", 1); are commented out - it stops working. Server just would not get data. Here are some parts of my library to give you clue how exactly sockets are made:
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
...............................................
memset( &name, 0, sizeof(name) );
name.sin_family = AF_INET;
name.sin_port = htons( port );
hostent* hostinfo = gethostbyname( address );
name.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
connect(s, (sockaddr*)&name, sizeof name)
Nothing fancy as you see. Maybe it is some unspoken rule that sending one byte of data to initialize connection is required or something? I am really confused here.
Edit:
Write function as requested. name variable is very same that is set in Connect call whose code is above.
virtual int Write( void* data, int size )
{
return sendto(s, (const char*)data, size, 0, (sockaddr*)&name, sizeof name);
}
Edit:
Also in select() loop i check only for sockets being readable. Could it be case that socket is not writable due to connection being initialized? If that is the case it should solve First sleep. But what about sending one byte then?

UDP Tx loop stops working every time at exactly 3970 packets, 14386 on my friends computer

I've been stuck at this issue for the last 4 days and I can't seem to figure it out. I'm trying to send data to myself using UDP packets so another program can read the bytes.
I can clearly read the packets but I only get up to 3970 before the UDP portion of the program hangs. Glut and everything else continues to run fine. I gave my friend the same code and he ran it on his computer. He got 14386 iterations before it hangs. variable temp will count the number of packets sent. -1 is bad. counter counts the while loop iterations. I'm following the example here:
http://msdn.microsoft.com/en-us/library/ms740148(v=vs.85).aspx
Example Code:
#include "stdafx.h"
#include <WinSock2.h> // don't forget to add in
//Project Properties>Linker>Input>Additional Dependences [Ws2_32.lib]
sockaddr_in dest;
sockaddr_in local;
WSAData data;
static void SUDP_init(void)
{
printf("--[UDP Socket Initialized]--\r\n");
WSAStartup( MAKEWORD( 2, 2 ), &data );
local.sin_family = AF_INET;
local.sin_addr.s_addr = inet_addr( "127.0.0.1" ); //same as localhost
local.sin_port = 6000;
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr( "127.0.0.1" );
dest.sin_port = htons( 6000 );
bind( socket( AF_INET, SOCK_DGRAM, 0 ), (sockaddr *)&local, sizeof(local) );
printf("Socket Bound...\r\n");
}
static int counter = 0;
int _tmain(int argc, _TCHAR* argv[])
{
SUDP_init();
while(1){
char packet[30];
sprintf(packet, "%0.3f,%0.3f,%0.3f",
55.4,
16.1,
-27.88);
int temp = sendto( socket( AF_INET, SOCK_DGRAM, 0 ), packet, strlen(packet), 0, (sockaddr *)&dest, sizeof(dest) );
if(temp>=1){
counter++;
}
printf("Bytes Sent: %d, Counter: %d\r\n",temp,counter);
}
return 0;
}
You are allocating new sockets in a loop (the first argument to sendto), you are also allocating another for bind, but these are never freed. You eventually run out of socket handles to allocate, hence your program hanging.
Instead, allocate a socket once in SUDP_init, store it instead of discarding it, then pass that to bind and sendto

Reopen connected datagram socket

I have a connection protocol that has been defined by our customer. Data are sent between two linux computers using UDP and TCP protocols. The IP addresses and ports are fixed on startup.
We are sending messages at 200 Hz and I have been using connect to save some time on the transmissions.
My problem is that if there is a communication error, I need to tear down the connections and reinitialise.
I have a problem with one of the UDP connections as it will not rebind to the required address and returns errno 22.
The code I am using is something like:
int
doConnect(int& sock, int local_port, char *local_ip, int remote_port, char *remote_ip)
{
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons(local_port);
inet_pton(local_ip,&addr.sin_addr.s_addr);
if (0 > bind(sock, (struct sockaddr*)&addr, sizeof(addr)))
{
printf("Bind Error errno = %d\n", errno);
return ERR_BIND;
}
memset(&addr, 0, sizeof(sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons(remote_port);
inet_pton(remote_ip,&addr.sin_addr.s_addr);
if (0 > connect(sock, (struct sockaddr*)&addr, sizeof(addr)))
{
printf("Connect Error errno = %d\n", errno);
return ERR_CONNECT;
}
return ERR_OK;
}
The way that this is used is like this:
int s1(-1), s2(-1);
doConnect(s1, 31003, "172.17.21.255", 31006, "172.17.21.1");
doConnect(s2, 31001, "172.17.21.3", 31004, "172.17.21.1");
When an error occurs
close(s1);
close(s2);
doConnect(s1, 31003, "172.17.21.255", 31006, "172.17.21.1");
doConnect(s2, 31001, "172.17.21.3", 31004, "172.17.21.1");
Here the local address is 172.17.21.3 and I am connecting to 172.17.21.1. s1 listens to a broadcast message.
s1 successfully reconnects to the remote machine, but s2 fails with error 22 from the call to bind.
I have tried explicitly calling bind and connect to an AF_UNSPEC address immediately before I close the socket. This doesn't solve the problem.
Are there any options that I should be using?
Perhaps you could try:
int val = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
I also suggest you double check that you're not passing the same socket to the two consecutive doConnect() calls (as errno 22 = EINVAL, which in the case of bind() appears to mean that the socket is already bound to an address).
The underlying socket layer might hold the port & IP address still open, even after your call to close. Try some of the following:
do a sleep(10) (or more) between the close and the call to doConnect again
configure the sockets using setsockopt with the SO_LINGER set to off
This actually happens more commonly with TCP connections, but I see no reason UDP can't have this problem as well.

Client is having trouble connecting to server using sockets?

My server is up and running (connecting through telnet worked so I know its functional) but my client cannot seem to establish a connection. I have a feeling it has something to do with the way I'm filling out the sockaddr_in serverAddr struct.
Can anyone please help? Thank you.
int clientSocket;
char hostname[256];
struct sockaddr_in serverAddr;
struct hostent *host;
socklen_t theirAddrSize;
gethostname(hostname, sizeof(hostname));
host = gethostbyname(hostname);
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr( host->h_name );
serverAddr.sin_port = htons( 30000 );
if ( clientSocket = socket( AF_INET, SOCK_STREAM , 0 ) == -1) {
cerr << "socket failed ; exiting..." << endl;
exit(1);
}
if ( connect( clientSocket , (struct sockaddr *) &serverAddr , sizeof(serverAddr) ) == -1 ) {
cerr << "connect failed ; exiting..." << endl;
exit(1);
}
connect always returns -1.
Instead of inet_addr(host->h_name), use host->h_addr_list[0].
Does this work?
memcpy(&serverAddr.sin_addr,
host->h_addr,
sizeof(serverAddr.sin_addr));
As far as I can see there's nothing wrong with the code you've posted here. It's pretty much identical with socket client code I've been writing for years. So the problem either lies elsewhere in the code, or it's in the data.
Ah - you've edited the code... and added some comments. OK, the return value from inet_addr is -1 (4294967295 == 0xFFFFFFFF == -1 == INADDR_NONE), so it doesn't seem to like what you're passing it.
You need to run the code through a debugger, concentrating on the calls to gethostname and gethostbyname. I'm assuming this is test code, since you're connecting to the same machine you're running on.
I did require the memcpy but alot of this headache stemmed from a very mindless syntax error:
if ( clientSocket = socket( AF_INET, SOCK_STREAM , 0 ) == -1)
I had to wrap the assignment in parenthesis before comparing it to -1.
if (( clientSocket = socket( AF_INET, SOCK_STREAM , 0 )) == -1)
Gah, you live you learn :)