I have a network application meant for a private LAN. I am doing my testing using loopback. When I test on the LAN the socket creation order does not matter. If I test using loop back 127.0.0.1 then there is a socket creation ordering issue. Why is it different on loop back?
Here are more details...
There is one server, and many client instances. The server is broad casting data over UDP. The clients receive the data and process it.
I need to have the network layer not care about the order in which either the server or clients start. It is hard to administer process creation for my case. The application instances should be able to start on the network in any order and just see the data broadcasted on the UDP port when it is sent.
But there is something in the way I setting up my UDP sockets which is forcing ordering to take place. I must start the clients, THEN start the server. If I start the clients AFTER the server doing the UDP broadcast, the client sockets do not receive the data. If I force a running server instance to tear down and rebuild its UDP socket, suddenly all the clients start receiving data.
There must be something wrong with how I creating the socket. The client and server code use a shared function library to make the UDP socket. So the server is sending on m_fdOut. Each instance of the client is receiving on m_fdIn.
What am I doing wrong here?
SOCKET m_fdIn;
SOCKET m_fdOut;
if ((m_fdIn = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
WARNF("socket failed, winsock error %d\n", WSAGetLastError());
exit(1);
}
if ((m_fdOut = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
WARNF("socket failed, winsock error %d\n", WSAGetLastError());
exit(1);
}
int sockopt = 1;
if (setsockopt(m_fdOut, SOL_SOCKET, SO_BROADCAST, (char *)&sockopt,
sizeof(sockopt)) < 0)
{
WARNF("setsockopt failed, winsock error %d\n", WSAGetLastError());
exit(1);
}
sockopt = readPreference<int>("SOL_RCVBUF", 512*1024);
if (setsockopt(m_fdIn, SOL_SOCKET, SO_RCVBUF, (char *)&sockopt, sizeof(sockopt)) < 0)
{
WARNF("setsockopt failed, winsock error %d\n", WSAGetLastError());
exit(1);
}
sockopt = 1;
if (setsockopt(m_fdIn, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt)) < 0)
{
WARNF("setsockopt failed, winsock error %d\n", WSAGetLastError());
exit(1);
}
sockopt = readPreference<int>("IP_MULTICAST_TTL", 32);
if (setsockopt(m_fdOut, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&sockopt, sizeof(sockopt)) < 0)
{
WARNF("setsockopt failed, winsock error %d\n", WSAGetLastError());
exit(1);
}
String destAdd = "255.255.255.255"
int portNumber = 1234;
int n1, n2, n3 ,n4;
if (sscanf(destAddr, "%d.%d.%d.%d", &n1, &n2, &n3, &n4) != 4)
{
n1 = n2 = n3 = n4 = 255;
}
u_long bcastAddr = (n1<<24) | (n2<<16) | (n3<<8) | n4;
outAddr.sin_family = AF_INET;
outAddr.sin_port = htons(portNumber);
outAddr.sin_addr.s_addr = htonl(bcastAddr);
struct sockaddr_in in_name;
in_name.sin_family = AF_INET;
in_name.sin_addr.s_addr = INADDR_ANY;
in_name.sin_port = htons(portNumber);
if (bind(m_fdIn, (struct sockaddr *)&in_name, sizeof(in_name)) < 0)
{
WARNF("bind failed, winsock error %d\n", WSAGetLastError());
exit(1);
}
So I did change the implementation from UDP broadcast to multicast. That seems to work in loopback so multiple processes can share the port.
Related
I'm currently using a Esp32 which presents, in addition to wifi, an ethernet interface.
I'm using the esp-idf v3.3 with FreeRTOS.
To use it I included the "esp_eth.h" library (https://docs.espressif.com/projects/esp-idf/en/release-v3.1/api-reference/ethernet/esp_eth.html#api-reference-phy-lan8720).
I'd like to use both Wifi and ethernet interfaces basing on what I want to do but selecting which one to use, is there a way?
The practical use is to receive a command through the ethernet interface (for example a site to ping), ping the server through the wifi interface and answer back to the ethernet interface the ping result.
How can I select which interface to use (i dont want that the ping is made through the ethernet or that the response go through the wifi).
#edit: i found the method netif_set_default(struct netif * netif), but i dont know if it is the best way to select the interface to use for the specific action(i should swap from one interface to another)
Just get the IP of the Ethernet interface, then bind a socket to that IP address.
struct in_addr iaddr = {0};
#if USE_ANY_IF
// Bind the socket to any address
iaddr.s_addr = htonl(INADDR_ANY);
#else
// bind only to the Ethernet interface
tcpip_adapter_ip_info_t ip_info = {0};
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip_info);
inet_addr_from_ip4addr(&iaddr, &ip_info.ip);
#endif
Then use it to bind a socket, for example:
static int create_multicast_ipv4_socket(struct in_addr bind_iaddr)
{
struct sockaddr_in saddr = {0};
int sock = -1;
int err = 0;
char addrbuf[32] = {0};
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0)
{
ESP_LOGE(V4TAG, "Failed to create socket. Error %d", errno);
return -1;
}
saddr.sin_addr.s_addr = bind_iaddr.s_addr; // what interface IP to bind to. Can be htonl(INADDR_ANY)
saddr.sin_family = PF_INET;
saddr.sin_port = htons(UDP_PORT);
inet_ntoa_r(saddr.sin_addr.s_addr, addrbuf, sizeof(addrbuf) - 1);
ESP_LOGI(TAG, "Binding to interface %s...", addrbuf);
err = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
if (err < 0)
{
ESP_LOGE(V4TAG, "Failed to bind socket. Error %d", errno);
goto err;
}
// Assign multicast TTL (set separately from normal interface TTL)
uint8_t ttl = MULTICAST_TTL;
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(uint8_t));
if (err < 0)
{
ESP_LOGE(V4TAG, "Failed to set IP_MULTICAST_TTL. Error %d", errno);
goto err;
}
// All set, socket is configured for sending
return sock;
err:
close(sock);
return -1;
}
I've looked and followed documentation from LwIP 2.0.2. My project contains the MQTT library supplied in the LwIP 2.0.2. I also found some help at https://dzone.com/articles/mqtt-with-lwip-and-the-nxp-frdm-k64f. I'm unable to get a connection, I've used free public MQTT broker but no hope in connection. I can ping my device. Am I doing something wrong?
static void mqtt_test(mqtt_client_t *mqtt_client)
if (mqtt_client_is_connected(&mqtt_client) == 1)
{
example_subscribe(&mqtt_client, NULL);
} else {
mqtt_do_connect(&mqtt_client);
}
}
when I call this method it always enters mqtt_do_connect() never connecting. Here is mqtt_do_connect
static void mqtt_do_connect(mqtt_client_t *mqtt_client)
{
ip4_addr_t broker_ipaddr;
struct mqtt_connect_client_info_t ci;
err_t err;
if (ipaddr_aton("52.58.177.181", &broker_ipaddr))
{
err = ERR_OK;
}
/* Setup an empty client info structure */
memset( & ci, 0, sizeof(ci));
/* Minimal amount of information required is client identifier, so set it here */
ci.client_id = "test";
/* Initiate client and connect to server, if this fails immediately an error code is returned
otherwise mqtt_connection_cb will be called with connection result after attempting
to establish a connection with the server.
For now MQTT version 3.1.1 is always used */
err = mqtt_client_connect(mqtt_client, & broker_ipaddr, 1883, mqtt_connection_cb, 0, & ci);
/* For now just print the result code if something goes wrong */
if (err != ERR_OK) {
printf("mqtt_connect return %d\n", err);
}
}
I've also noticed in the method mqtt_client_connect in mqtt.c that this exists:
/* Any local address, pick random local port number */
err = tcp_bind(client->conn, IP_ADDR_ANY, 0);
why is this needed? If I replace IP_ADDR_ANY to my local address of the static IP of the device it runs through without throwing a error but no callback mqtt_connection_cb is then called.
I've also initialized the TCP/IP stack as mentioned with static IP. I'm using NO_SYS as 1 but will move it over to FreeRTOS but baby steps first.
I haven't found much support on MQTT in LwIP implementation, am I missing something obvious, any help will be appreciated.
I've used MQTTfx to run a test or two on the broker with good response but nothing from my embedded device (Atmel SAME54).
I've found the solution. I ran my TCP setup in a FreeRTOS thread and opened a socket
static void mqtt_start(void *p)
{
struct sockaddr_in address;
int s_create, new_socket;
int addrlen = sizeof(address);
int opt = 1;
int socket_check;
sys_sem_t sem;
err_t err_sem;
err_sem = sys_sem_new(&sem, 0); /* Create a new semaphore. */
tcpip_init(tcpip_init_done, &sem);
sys_sem_wait(&sem); /* Block until the lwIP stack is initialized. */
sys_sem_free(&sem); /* Free the semaphore. */
/*Create a socket*/
s_create = socket(AF_INET, 1, 0);
setsockopt(s_create, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(IPADDR_ANY);
address.sin_port = htons(HTTP_PORT);
/* bind the connection to port */
socket_check = bind(s_create, (struct sockaddr *)&address, sizeof(address));
if (socket_check < 0) {
LWIP_DEBUGF(LWIP_DBG_ON, ("Bind error=%d\n", socket_check));
goto socket_close;
}
/* tell the connection to listen for incoming connection requests */
listen(s_create, 3);
mqtt_connect(&mqtt_client);
for (;;) {
new_socket = accept(s_create, (struct sockaddr *)&address, (socklen_t *)&addrlen);
socket_close:
close(new_socket);
}
}
I also had a problem with my initialization of my mqtt client, placed a watch on it and saw the struct wasn't initializing. I initialized it globally
mqtt_client_t mqtt_client;
Then use it later in mqtt_start.
Trying to implement a JB check for non-default open ports (i.e., 22/TCP SSH):
/**
Checks for non-standard ports
*/
inline int isPortOpen(short port)__attribute__((always_inline));
-(BOOL)isPortOpen:(short) port
{
struct sockaddr_in addr;
int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if(inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr)) {
int result = connect(sock,(struct sockaddr *)&addr, sizeof(addr));
// error :(
int w00t = errno;
NSLog(#"Error: %i",w00t);
if(result == 0){
NSLog(#"FAILED JB CHECK -- non-standard port open!");
return YES;
}
close(sock);
}
NSLog(#"PASSED JB CHECK -- non-standard ports closed.");
return NO;
}
But connect() fails (result is -1) and the errno is 1 -- EPERM
https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man2/intro.2.html
1 EPERM Operation not permitted. An attempt was made to perform an operation
limited to processes with appropriate privileges or to the
owner of a file or other resources.
Looking at the manual for connect(), EPERM is not one of the possible return errors.
https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man2/connect.2.html
So, the only reason I can see for getting EPERM is the sandbox, but:
Running on a jailbroken iPod (iOS 8.4)
The container seatbelt profile allows outbound network connections by default
I'd like to understand what's happening. Note that I've tried connecting to the wireless interface as well, instead of loopback.
I'm trying to implement simple traceroute for the iOS. Everything seems to work fine, except that somehow when I run my application on simulator or on the device it finds only a few (6-7) first routers on the way when the CLI traceroute finds all 14 routers.
const char *c = "www.gmail.com";
struct hostent *host_entry = gethostbyname(c);
char *ip_addr;
ip_addr = inet_ntoa(*((struct in_addr *)host_entry->h_addr_list[0]));
struct sockaddr_in destination, fromAddr;
int recv_sock;
int send_sock;
// Creting Sockets///
if ((recv_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)) <
0) // using UDP socket.
{
NSLog(#"Could not cretae recv_sock.\n");
}
if ((send_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
NSLog(#"Could not cretae send_sock.\n");
}
memset(&destination, 0, sizeof(destination));
destination.sin_family = AF_INET;
destination.sin_addr.s_addr = inet_addr(ip_addr);
destination.sin_port = htons(80);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 10000;
setsockopt(recv_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
sizeof(struct timeval));
char *cmsg = "GET / HTTP/1.1\r\n\r\n";
int max_ttl = 20;
int num_attempts = 5;
socklen_t n = sizeof(fromAddr);
char buf[100];
for (int ttl = 1; ttl <= max_ttl; ttl++) {
memset(&fromAddr, 0, sizeof(fromAddr));
if (setsockopt(send_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
NSLog(#"error in setsockopt\n");
for (int try = 0; try < num_attempts; try ++) {
if (sendto(send_sock, cmsg, sizeof(cmsg), 0,
(struct sockaddr *)&destination,
sizeof(destination)) != sizeof(cmsg))
NSLog(#"error in send to...\n#");
int res = 0;
if ((res = recvfrom(recv_sock, buf, 100, 0, (struct sockaddr *)&fromAddr,
&n)) < 0) {
NSLog(#"an error: %s; recvfrom returned %d\n", strerror(errno), res);
} else {
char display[16] = {0};
inet_ntop(AF_INET, &fromAddr.sin_addr.s_addr, display, sizeof(display));
NSLog(#"Received packet from%s for TTL=%d\n", display, ttl);
break;
}
}
}
I have tried to bind the send socket but have same results and I can't use Sock_raw on iOS. I tried to run it on my mac and got same results. The error I get is "Resource temporarily unavailable;" for the recvfrom(). Why is that? How can I fix it?
The EAGAIN error ( producing "Resource temporarily unavailable;" string) could be raised by the timeout of the receiving socket.
Since you set just 10000 microseconds as read timeout (that's really short IMHO) with this line...
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 10000;
setsockopt(recv_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
... it's possibile that the longer the way (i mean the number of router you have to pass through), the more chance you have to incour in this situation.
Try to raise timeout value and let us know if it got better.
EDIT
I tried the source code under linux and i noticed two kind of problems.
As mentioned above: Timeouts
Problem with the 80 port
I just raised the timeout and used a port different than 80 (in my case i sent udp message to 40000 port) and i got back all the hops just like traceroute command.
I'm not sure why this behaviour occour. Maybe some kind of "possible malicious packet alarm" gets triggered by the router that discards it
FURTHER EDIT
Look at this link: man traceroute
In the List Of Available Methods section you can find many ways to achieve what you need. Your method is similar to the default one, stating:
Probe packets are udp datagrams with so-called "unlikely" destination ports. The "unlikely" port of the first probe is 33434, then for each next probe it is incremented by one. Since the ports are expected to be unused, the destination host normally returns "icmp unreach port" as a final response. (Nobody knows what happens when some application listens for such ports, though).
So, if you need to full emulate the behaviour of the common Linux traceroute you have to increase by 1 the destination port, everytime the TTL increase (or everytime you can't get a response IMHO)
MAYBE, sometimes your command doesn't work on certain ports because the router is listening to the latter (as suggested by Linux manual and underlined in bold by me).
I am working on an app that uses UDP port 6785 to discover network connected dataloggers. My app attempts to call bind() as follows:
int socket_handle;
int error = 0;
socket_handle = socket(AF_INET, SOCK_DGRAM, 0);
if(socket_handle < 0)
error = errno;
if(error == 0)
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(6785);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
error = bind(socket_handle, (struct sockaddr const *)&addr, sizeof(addr));
}
The error returned from bind() is error 49 (can't assign requested address). Is this happening because of a conflict with some internal device service or is it being blocked by the OS for some unknown reason?
It turns out that the failure does not occur if I have VPN turned off. I had to enable VPN in order to access our local network from wifi.
Try this before calling bind(). This solves the problem if the port is being blocked by a TIME_WAIT
int optval = 1;
setsockopt(socket_handle, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));