How to get IP used by sendto function? - sockets

When the sender has multiple network cards, this function sendto chooses random ip to send the packet.
So get the ip address used by sendto?
Code:
fd = socket(AF_INET, SOCK_DGRAM, 0);
sendto(fd, buf, len, 0, (struct sockaddr*)&servaddr, sizeof(servaddr));

It doesn't choose a random IP. It uses the OS's routing table to decide which local IP has the best chance of routing the data to the destination address. However, there is no way to query which IP sendto() actually chose to use. You could access the OS's routing table directly and try to figure it out manually, but the better option is to just bind() the socket to the specific IP that you want sendto() to use as the sending IP, eg:
fd = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in localaddr;
memset(&localaddr, 0, sizeof(localaddr));
localaddr.sin_family = AF_INET;
localaddr.sin_addr.s_addr = inet_addr("192.168.0.1"); // the desired local IP
bind(fd, (struct sockaddr*)&localaddr, sizeof(localaddr));
sendto(fd, buf, len, 0, (struct sockaddr*)&servaddr, sizeof(servaddr));

Related

ESP32 Multicast UDP High losses (receiving)

I'm developing device base on ESP32 module that have a UDP socket open only to receive broadcast packets on one port (7890 to be exact). The problem is that the data losses are high - around 90%. My test setup is:
ESP32 - connected to WiFi network with open UDP receing task (code belowe)
PC connected to the same netwer via LAN with UDP terminal set to brodacast to remote: 192.168.10.255:7890
Mobile phone connected to WiFi with UDP terminal set to brodacast to remote: 192.168.10.255:7890
When I send something from PC or mobile phone there is no data lossage between Mobile phone and PC but ESP32 receive around 10% of data that I transmit from both of senders. If I change from multicast to unicast on PC or Phone to send data to ESP32, it work without problem.
I know that UDP does not guarantee the delivery but 10% efficiency seems for me to be super low, especially when it seems that there is no problem with busy network because PC and mobile received the data all the time.
Do you have any suggestion to the code or some setting that can be changed in menu config ?
At the moment my application have only two tasks:
WiFi Task that after connection is just waiting for event
UDP Task that the code is below
Update 04.07.2018 (13:15)
Problem disappear when I don't initialize bluetooth. Sorry that I didn't mention previously about BT being initialized but I kept me initializing function from my normal program that have a lot more tasks (BT included) and totally forgot about this myself.
Anyway - do you think that there is some issue with sharing the resource or is it some physical interference ? I'm using ESP32-DevKitC that is on the breadboard, so no additional shielding is present.
#define PORT_NUMBER 7890
#define BUFLEN 100
void udp_task(void *pvParameter)
{
struct sockaddr_in clientAddress;
struct sockaddr_in serverAddress;
struct sockaddr_in si_other;
unsigned int slen = sizeof(si_other);
unsigned int recv_len;
char buf[BUFLEN];
int sock;
printf("UDP Task: Opening..\n");
int ret;
ret = UDP_List_Open(&clientAddress, &serverAddress, &sock);
if(ret == 0)
{
printf("UDP Task: Open\n");
}
else
{
printf("UDP Task: Can't open\n");
}
while(1)
{
memset(buf,0,100);
if ((recv_len = recvfrom(sock, buf, 100, 0, (struct sockaddr *) &si_other, &slen)) == -1)
{
printf("UDP error\n");
break;
}
sendto(sock, buf, recv_len, 0, (struct sockaddr *)&si_other, sizeof(si_other));
printf("UDP Task: Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
printf("UDP Task: Data: %s -- %d\n" , buf, recv_len);
}
while(1)
{
vTaskDelay(100 / portTICK_RATE_MS);
}
}
int UDP_List_Open(struct sockaddr_in* clientAddress, struct sockaddr_in* serverAddress, int* sock)
{
// Create a socket that we will listen upon.
*sock = socket(AF_INET, SOCK_DGRAM, 0);
if (*sock < 0)
{
printf("UDP List Open: Socket error\n");
return 1;
}
// Bind our server socket to a port.
serverAddress->sin_family = AF_INET;
serverAddress->sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress->sin_port = htons(PORT_NUMBER);
int rc = bind(*sock, serverAddress, sizeof(*serverAddress));
if (rc < 0)
{
printf("UDP List Open: Bind error\n");
return 2;
}
return 0;
}
Even though UDP is considered fire and forget, (unlike TCP), unicast UDP through WiFi is reliable because reliability is built into the WiFi protocol. But this can work for Unicast only because there is one known recipient. Multicast UDP is unreliable because there are no checks and retries.
I had the same problem when I was trying to use multicast UDP with the ESP8266. It caused me to dig deeper into the issue. In the end I use UDP multicast for discovery but then switch to Unicast UDP for subsequent transfers.
See Multicast Wifi Problem Statement
https://tools.ietf.org/id/draft-mcbride-mboned-wifi-mcast-problem-statement-01.html

VxWorks 6.8: setsockopt with IP_ADD_MEMBERSHIP returning EADDRNOTAVAIL

I am trying to set up a socket to receive multicast UDP packets on VxWorks 6.8.
sin.sin_len = (u_char)sizeof (sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/* UDP port number to match for the received packets */
sin.sin_port = htons (mcastPort);
/* bind a port number to the socket */
if (bind(sockDesc, (struct sockaddr *)&sin, sizeof(sin)) != 0)
{
perror("bind");
status = errno;
goto cleanUp;
}
/* fill in the argument structure to join the multicast group */
/* initialize the multicast address to join */
ipMreq.imr_multiaddr.s_addr = inet_addr (mcastAddr);
/* unicast interface addr from which to receive the multicast packets */
ipMreq.imr_interface.s_addr = inet_addr (ifAddr);
printf ("Interface address on which to receive multicast packets: %s\n", ifAddr);
/* set the socket option to join the MULTICAST group */
int code = setsockopt (sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char *)&ipMreq,
sizeof (ipMreq));
The setsockopt() call is returning -1 and errno is being set to 49 or EADDRNOTAVAIL. On wireshark, when we perform setsockopt I can see a properly formed group unsubscribe packet being sent out from the right port/interface. All different combinations of interfaces, ports, and multicast groups give the same result.
I am unable to debug very far into setsockopt as there doesnt seem to be anything wrong before the task calls ipcom_pipe_send and ipnet_usr_sock_pipe_recv, and after the recv call errno is set. I dont know how to debug the relevant tNetTask code that may be generating the error.
It could be that there's an issue with the interface index you supplied. Define ipMreq to be a struct ip_mreq, which does not have the imr_ifindex, instead of a struct ip_mreqn and remove the ipMreq.imr_ifindex = 2; line.

connect to remote server using sockets unix

In unix, I want to make a client program connect to a server running on different machine. For this, I need to enter the ip address of server through keyboard and then pass that ip address in the connect() system call of client. I tried reading as a string, and passing it.But it didnt work. Is there any specific way to pass the ip address?
Assuming IPv4, the function you're looking for is inet_addr, which converts the string representation of an IPv4 address to a numerical value which can be passed into various socket functions:
int get_connection(const char *ip, int port)
{
int sock;
struct sockaddr_in sin;
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(ip);
sin.sin_port = htons(port);
if ((sock=socket(AF_INET,SOCK_STREAM,0))==-1) {
perror("Error creating socket");
return -1;
}
if (connect(sock,(struct sockaddr *)&sin,sizeof(sin))==-1) {
perror("Couldn't connect");
close(sock);
return -1;
}
return sock;
}

client-server code. How to bind the data connection to a specific port

I am trying to do the following:
Let us say I start a TCPServer on machine X. Now, I want to connect to the TCPServer from machine Y, but I want to specify the ports (both sender and receiver), on which the data communication should take place. Also, the TCPServer handles multiple clients at the same time.
MachineX: ./TCPServer
MachineY: ./TCPClient -SP 5000 -DP 5000
I have written the code for a multithreaded server (using C UNIX), and it works fine. Basically, it spawns one thread per connection. But I am not sure how to include the above functionality.
Thank you for your time!
Prior to calling connect(), call bind().
I'm assuming you had to do this for the server code, right? Otherwise, how do you get your server (running on MachineX) to listen on port 5000.
In any case, here's a C example of binding to localhost port 5000.
Example:
int sock = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in addrRemote = {};
sockaddr_in addrLocal = {}; // zero init so that sin_addr is already INADDR_ANY;
int result;
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = htons(5000);
result = bind(sock, (sockaddr*)&addrLocal, sizeof(addrLocal));
if (result < 0)
return;
addrRemote.sin_family = AF_INET;
addrRemote.sin_port = htons(5000);
addrRemote.sin_addr = <ip of MachineX in network byte order>;
result = connect(sock, (sockaddr*)&addrRemote, sizeof(addrRemote));
if (result < 0)
return;
It's assumed that TCPServer running on machine X is listening on port 5000.

Retrieving the protocol of a socket in winsock

I am working in networking reliability simulation, I need to simulate packet dropping based on a quality of service percentage. Currently I have a DLL that hooks into send, sendto, recv and recvfrom. My hooks then 'drop' packets based on the quality of service.
I just need to apply the hook to UDP packets, and not disturb TCP (TCP is used for remote debugging).
Is there a way that I can query WinSock for the protocol that a socket is bound to?
int WSAAPI HookedSend(SOCKET s, const char FAR * buf, int len, int flags)
{
//if(s is UDP)
//Drop according to QOS
else
//Send TCP packets undisturbed
return send(s, buf, len, flags);
}
I think you could get the socket type by using getsockopt:
int optVal;
int optLen = sizeof(int);
getsockopt(socket,
SOL_SOCKET,
SO_TYPE,
(char*)&optVal,
&optLen);
if(optVal = SOCK_STREAM)
printf("This is a TCP socket.\n");
else if(optVal = SOCK_DGRAM)
printf("This is a UTP socket.\n");
else
printf("Error");