I used two sockets in the same process, one acting as multicast server and the other acting as multicast client. I am trying to combine both server and client functionality in a single socket. Could not succeed till now. Did any one tried making a single socket as multicast server and client. Is it possible? If not any reference that states the limitation would be appreciated. Thank a lot.
It is possible, at least on windows. Try following example(without error checking):
SOCKET the_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("192.168.1.117");
service.sin_port = htons(56565);
int ret = bind(the_socket, (SOCKADDR *) &service, sizeof (service));
unsigned int grpaddr = inet_addr("224.4.4.44");
unsigned int iaddr = inet_addr("192.168.1.117");
//You should have the equivalent function in your existing client
//to join the multicast group
ret = join_source_group(the_socket, grpaddr, service.sin_addr.s_addr, iaddr);
std::string data = "AA";
sockaddr_in group;
group.sin_family = AF_INET;
group.sin_addr.s_addr = inet_addr("224.4.4.44");
group.sin_port = htons(56565);
ret = sendto(the_socket, data.c_str(), data.length(), 0, (const sockaddr*)&group, sizeof(group));
char recvdata[3] = {0};
ret = recv(the_socket, recvdata, 3, 0);
leave_source_group(the_socket, grpaddr, service.sin_addr.s_addr, iaddr);
"Server" and "Client" are not terms which really fit very comfortably into non connection-based sockets. Particularly with multicasting.
So a "Multicast receiver" and "Multicast sender" might be more appropriate.
You can of course, use the same socket to do both at once. It is not mandatory to join a group to send messages to it, but if you do, you may receive your own messages (in some OSs this is optional, for instancce using Linux's setsockopt IP_MULTICAST_LOOP).
"Server" and "client" are really concepts which work at a higher layer than multicasting. I hope that you can explain what you are trying to do better, maybe in another question.
Whether a multicast sender or receiver is the client or server, depends entirely on the application.
Related
I am writing a C++ multicasting application on Linux Ubuntu.
In my C++ multicast sender class I do this:
uint16_t port = 5678;
const char* group = "239.128.128.128";
int fd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(group);
addr.sin_port = htons(port);
const char* buf = "Hi there";
size_t bytes_to_write = 8;
size_t bytes_sent = sendto(fd, buf, bytes_to_write, 0, (struct sockaddr*) &addr, sizeof(addr));
Is there any way to configure the file descriptor so that I can call write() rather than sendto()? I would have thought there would be a setsockopt option or similar to do this?
Yes.
Per the documentation man 7 udp
When
connect(2) is called on the socket, the default destination address
is set and datagrams can now be sent using send(2) or write(2)
without specifying a destination address.
and, for generality, the POSIX spec for connect says
If the initiating socket is not connection-mode, then connect() shall set the socket's peer address, and no connection is made. For SOCK_DGRAM sockets, the peer address identifies where all datagrams are sent on subsequent send() functions, and limits the remote sender for subsequent recv() functions.
It's always worth checking the documentation for these, things, it isn't that impenetrable. FWIW I couldn't remember immediately whether you need connect() or bind() for this, and it took me a few seconds to find out.
My code is based on the book "Network Programming for Microsoft Windows Second Edition", which can be found online as a PDF.
My code for the server application is:
#include <iostream>
#include <winsock2.h>
int main(void)
{
WSADATA wsaData;
SOCKET ReceivingSocket;
SOCKADDR_IN ReceiverAddr;
int Port = 5150;
char buffer;
SOCKADDR_IN SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
WSAStartup(MAKEWORD(2,2), &wsaData);
ReceivingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ReceiverAddr.sin_family = AF_INET;
ReceiverAddr.sin_port = htons(Port);
ReceiverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(ReceivingSocket, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr));
recvfrom(ReceivingSocket, &buffer, 1, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize);
std::cout << buffer << std::endl;
buffer = 'b';
sendto(ReceivingSocket, &buffer, 1, 0, (SOCKADDR*)&SenderAddr, SenderAddrSize);
std::cin.get();
closesocket(ReceivingSocket);
WSACleanup();
}
And for the client application is:
#include <winsock2.h>
#include <iostream>
int main()
{
WSADATA wsaData;
SOCKET SendingSocket;
SOCKADDR_IN ReceiverAddr;
SOCKADDR_IN ex;
int Port = 5150;
char buffer = 'a';
WSAStartup(MAKEWORD(2,2), &wsaData);
SendingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ReceiverAddr.sin_family = AF_INET;
ReceiverAddr.sin_port = htons(Port);
ReceiverAddr.sin_addr.s_addr = inet_addr("-->insert ip here<--");
sendto(SendingSocket, &buffer, 1, 0, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr));
int len = sizeof (ex);
recvfrom(SendingSocket, &buffer, 1, 0, (SOCKADDR*)&ex, &len);
std::cout << buffer << std::endl;
std::cin.get();
closesocket(SendingSocket);
WSACleanup();
}
When I insert a local IP, the code works perfectly fine - the applications detect each other and exchange buffers. But when I insert my global IP, the applications don't detect each other. Is it a problem with the code, or something I have to change when using a global IP, or something wrong with my network settings?
To clarify:
When I said about "inserting IP address", I meant writing it instead of "-->insert ip here<--".
By local IP, I meant my computer's local IP address, checked in the console using the ipconfig command.
By global IP, I meant the global IP of my router, which I checked on myglobalip.com, and I forwarded port 5150 to my local IP address.
This might be a bit off topic, but if it's something wrong with network settings, I would appreciate if you could give a link to a good tutorial because I couldn't find one that worked.
Nice code. Nice and simple. All I had to do was cut and paste (and add #pragma comment (lib, "ws2_32.lib")).
Are the client and the server both running on your LAN? If so, my tests indicate that they won't be able to talk to each other via your router's external IP address. This is because the router doesn't loop back packets sent out through its ADSL / VDSL port (why would it?) so they just disappear into the ether. I tried enabling both the DMZ and port forwarding on my router (at minimum, you need one or the other) but no dice, which was what I was expecting.
So to test this, you will need the help of a friend with a router of his own. Let's suppose he is running the client. You will then need to put your server machine into your router's DMZ or (better, because it's safer) set up port forwarding for UDP port 5150 on your router to the server machine. In either case, give that machine a static IP address on your LAN else it might move. Then you have a chance of seeing this work.
Our friends over at superuser have this to say about sending UDP packets via [routers implementing] NAT (which is what you will have there) and getting an answer back:
IF Machine A sends [a UDP] frame from the same source port as the destination port ("Port N"), and IF the NAT is able to preserve that source port (i.e. it's configured to preserve source ports when possible, and that source port is not in use), THEN you can expect a reply to "Port N" to get back to Machine A.
But the problem currently is that nothing is listening. Certainly not your server program.
I'm using winsocks and I am coding an IDS/Honeypot, this is just a small section of it, because at the moment I want the server to listen on multiple sockets (7) and accept the connections, but I've tried to dynamically create the sockets with an array (and the listener etc) but I am still having trouble - I've tried it multiple ways but so far, all I've managed to do is get it working successfully on ONE socket, and LISTEN to all sockets, but not accept them.
So, this was my last attempt but not sure, maybe I need to use threads or declare the sockets differently?
So far, in this small test code, I want:
Initialize server
listen on all 7 ports (1111,2222 ...etc)
Accept an incoming connection on ANY of them
display both messages on client/server
drop the connection
and continue
It's a little sloppy I know, but here is the code so far and I think you can see where I am going with it:
#include <iostream>
#include <winsock2.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")
int main()
{
std::cout<<"Honeypot server [test #1] by Dreamwalker"<<std::endl;
WSADATA wsa;
SOCKET s[7] , new_socket[7];
struct sockaddr_in server , client;
int c, port[7] = {1111,2222,3333,4444,5555,6666,7777};
char *message;
std::cout<<"\nInitialising Winsock and other components...";
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
std::cout<<"Failed. Error Code :"<<WSAGetLastError()<<std::endl;
return 1;
}
//!IMPORTANT: create multiple new sockets on different ports
int i = 0;
for( i = 0; i < 7; i++)
{
//Create socket
if((s[i] = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
std::cout<<"Could not create socket : "<< WSAGetLastError()<<std::endl;
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( port[i] );
//Bind
if( bind(s[i] ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
std::cout<<"Bind failed with error code : "<< WSAGetLastError()<<std::endl;
}
/*!ALL CREATION CHECKING DONE, now create multiple sockets on the server
and listen for connections*/
c = sizeof(struct sockaddr_in);
listen(s[i] , SOMAXCONN);
}
///ALL INITIALIZED
std::cout<<"DONE!"<<std::endl;
//Listen/accept incoming connections
std::cout<<"Now listening for connections"<<std::endl;
new_socket[i] = accept(s[i] , (struct sockaddr *)&client, &c);
if (new_socket[i] == INVALID_SOCKET)
{
std::cout<<"accept failed with error code : "<< WSAGetLastError()<<std::endl;
}
//Accepted connection
else{
std::cout<<"Someone has connected to this machine!"<<std::endl;
message = "Hello Client , I have received your connection.\n";
send(new_socket[i] , message , strlen(message) , 0);
closesocket(s[i]);
}
std::cout<<"FINISHED"<<std::endl;
WSACleanup();
getchar();
return 0;
}
And now it's throwing a runtime error as well:
WSAENOTSOCK
10038
Socket operation on nonsocket.
An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket,
or for select, a member of an fd_set was not valid.
Which (including debugging) indicates that the socket isn't declared properly when creating on an array, advice?
You code to create/bind/listen is all good. Then:
new_socket[i] = accept(s[i] , (struct sockaddr *)&client, &c);
Firstly, by the time this runs you're outside the loop, and i is 7 which is past the end of the array of sockets, which is why you get the not-a-socket error.
Secondly, accept() is a blocking call, so you can't just call accept() on all the sockets from the same thread the way you did for listen. You need to either have a separate thread block in accept() for each of the ports, or find out which one has a client connection attempt in progress using e.g. select (or epoll - does Windows have that?), then accept() a client on that specific socket (but then you've still got to either create a thread to handle the client read/recvs and write/sends or use select/epoll to find out when there's input ready to read, or more space in output buffers for transmission). There's also a race condition to be wary of if you use select/epoll - a listening socket might signal readiness for accepting a client connection, but by the time you call accept() that connection attempt's failed and forgotten, then if the listening socket hasn't been set to non-blocking mode it'll hang there waiting for another client to connect to that specific socket. IMHO, this is a case where threading is actually easier.
I think it's more "Windowsy" to use IO Completion Ports (you might want to Google), but AFAIK they're totally unportable. Winsock's not an exact match for BSD sockets, but the porting or dual-support effort's small.
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?
I am writing a small program that tests an UDP network service. The implementation of the service is allowed to create a new socket for the session and respond to the client from there, at which point the client is then required to talk to this address (similar to TFTP).
Minimal client sans error checking looks like this:
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in destaddr = { ... };
MSGBUF msg[] = { ... };
DWORD sent;
WSASendTo(fd, msg, sizeof msg / sizeof *msg, &sent, 0, (sockaddr *)sa, sizeof sa, 0, 0);
char buffer[4096];
MSGBUF rcvmsg = { sizeof buffer, buffer };
DWORD received;
sockaddr_storage sa;
socklen_t sa_len = sizeof sa;
DWORD flags = 0;
WSARecvFrom(fd, &rcvmsg, 1, &received, &flags, (sockaddr *)&sa, &sa_len, 0, 0);
The client works fine if the server responds from the same address and port that the initial message was sent to, however replies from another port are silently discarded and the client hangs in WSARecvFrom.
Explicitly binding the socket to { AF_INET, INADDR_ANY, 0 } to force assignment of a local port, or invoking listen(fd, 5); makes no difference, as expected.
Is there anything in WSASendTo that implicitly connects an UDP socket, and if so, what should I do to avoid this?
UDP doesn't have connections. Datagrams are sent to and from ports; it's one-way communication.
It sounds to me like your server is letting itself be assigned a temporary port (i.e. passing 0 as the port in sockaddr_in), instead of using a specific port. This won't work.
Since UDP has no concept of a connection, each time you send data, it could be sent from a different port; the first send doesn't reserve the port that it was given, it just sends a datagram from it and then lets it go.
Your server should be binding itself to a specific port.
Meh, it was a firewall issue. Adding the application to the list of programs allowed to receive incoming traffic fixed the issue.