I'm currently working on a project need to broadcast the data packet to a common port D88 for every second, but the client can not receive the data packet. I'm not sure I'm using the right way to send the packet.
int sockfdBroad;
struct sockaddr_in addrBroad;
swStat.packetBroadSent=0;
sockfdBroad=socket(AF_INET,SOCK_DGRAM,0);
bzero(&addrBroad,sizeof(addrBroad));
addrBroad.sin_family = AF_INET;
addrBroad.sin_addr.s_addr=inet_addr("192.168.1.255");
addrBroad.sin_port=htons(3464);
if ((cycles%1000)==0)
{
currenttime = getMicrosTimeStamp();
createTimePacket(bufferTime,currenttime,Odroid_Trigger);
sendto(sockfdBroad,bufferTime,PACKET_LENGTH_TIME,0,(struct sockaddr *)&addrBroad,sizeof(addrBroad));
swStat.packetBroadSent++;
}
Assuming that the netmask for 192.168.1.255 is 255.255.255.0, 192.168.1.255 is a broadcast address. From man ip(7):
Datagrams to broadcast addresses can be only sent or received when the SO_BROADCAST socket flag is set.
In other words, both the sender and the receiver must do:
int value = 1;
if(-1 == setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &value, sizeof value))
// Handle error.
If you check the return value of sendto it must be -1 and errno == EACCESS. Always check the return values.
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.
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.
I capture all the packets in one side with help of nfqueue, "record" them (all the data: ip info, next protocol info etc) with nfq_get_payload and deliver them into another side with help of udp. How can I restore this packet on another side and then send to myself(2 side) like there is no udp-encapsulation between? Should I use some nfqueue API or I have to implement all the protocols packet creation (UDP, ICMP, TCP, etc)? And how should I send this restored packet?
Ok, I successfully recreated and sent forward my packet encapsulated in UDP. After recreation I needed to send this packet to another IP, but you can use original destination address. So the code snippet:
char *full_packet;
int size;
// some actions to get full_packet and size from UDP packet
// assume you recreated this: int size = nfq_get_payload(nfa, &full_packet);
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
// also optional string needed in my case:
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, "wlan0", strlen("wlan0"));
if (sock == -1) {
perror("socket() failed");
return 1;
}
struct sockaddr_in to;
struct ip *iph = (struct ip *)full_packet;
to.sin_addr.s_addr = inet_addr("192.168.0.107"); // here you can set IP address where you need send this packet
to.sin_family = AF_INET;
int bytes = sendto(sock, full_packet, size, 0, (struct sockaddr*) &to, sizeof(to));
if (bytes == -1) {
perror("send() failed");
return 1;
}
I hope this will help somebody
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.
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.