udp server on iOS - ios

I'm trying to send some up sensor data from arduino to my iPhone and i found here (http://www.benripley.com/development/ios/udp-server-on-iphone/) and I run it with some small mods to make it compile on a viewController I display the data and everything works perfectly. But when I leave the view and go back, probably because it tries to start the server again, the app crashes. i tried to move the code to the appDelegate to start the server on launch but the app crashes on launch. even if I try only to start the server on launch and start reading by the time I enter the view and the same thing happens. Any idea?
here is the code:
#include < sys/socket.h >
#include < arpa/inet.h >
#include < errno.h >
#define UDP 17
typedef struct sockaddr_in sockaddr_in;
- (void)startServer {
NSLog(#"UDP Server started...");
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = htons(5009);
// bind the socket to our address
if (-1 == bind(sock,(struct sockaddr *)&sa, sizeof(struct sockaddr)))
{
perror("error bind failed");
close(sock);
exit(EXIT_FAILURE);
}
for (;;)
{
recsize = recvfrom(sock,
(void *)buffer,
1024,
0,
(struct sockaddr *)&sa,
&fromlen);
if (recsize < 0)
fprintf(stderr, "%s\n", strerror(errno));
msg = [NSString stringWithFormat:#"%s", buffer];
NSLog(msg);
}
}
and the actual call is this:
[NSThread detachNewThreadSelector:#selector(startServer)
toTarget:self
withObject:nil];

Related

How to select which network interface to use in a ESP32

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;
}

How to set up a UNIX domain socket in iOS?

I am trying to set up a UNIX domain socket in iOS. According to https://iphonedevwiki.net/index.php/Unix_sockets, this is the code that I used to set up the socket on the server side:
const char *socket_path = "/var/run/myserver.socket";
// setup socket
struct sockaddr_un local;
strcpy(local.sun_path, socket_path);
unlink(local.sun_path);
local.sun_family = AF_UNIX;
int listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
printf("listenfd: %d\n", listenfd);
// start the server
int r = -1;
while(r != 0) {
r = bind(listenfd, (struct sockaddr*)&local, sizeof(local));
printf("bind: %d\n", r);
usleep(200 * 1000);
}
int one = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
// start listening for new connections
r = -1;
while(r != 0) {
r = listen(listenfd, 20);
printf("listen: %d\n", r);
usleep(200 * 1000);
}
// wait for new connection, and then process it
int connfd = -1;
while(true) {
if(connfd == -1) {
// wait for new connection
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
printf("new connfd: %d\n", connfd);
}
// process incoming data
char buffer[4096];
int len = recv(connfd, buffer, sizeof(buffer), 0);
if(len == 0) {
printf("connfd %d disconnected!\n", connfd);
connfd = -1;
continue;
} else {
printf("connfd %d recieved data: %s", connfd, buffer);
// send some data back (optional)
const char *response = "got it!\n";
send(connfd, response, strlen(response) + 1, 0);
}
}
However, when I run this code on my iPhone, I got this in the console:
listenfd: 3
bind: -1
bind: -1
bind: -1
bind: -1
bind: -1
...
It looks like there is a problem when we do bind() as it returns -1, I want to know what I am doing wrong in the code?
The errno is 1, which is OPERATION_NOT_PERMITTED
You are not allowed to create objects in /var/run on iOS. You need to put the socket in a directory where you are allowed to create objects, like FileManager.shared.temporaryDirectory.

IOS UDP recvfrom works when in Blocking but not when Non-Bocking

When I comment out the code that turn off blocking everything works fine, but when I leave the non blocking code in I never get any data from recvfrom. (Received bytes is always 0) Here is the code with the blocking statement commented out. I am new to Xcode and IOS but have created UDP code for .NET.
// Create Socket
int Handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (Handle <=0){
printf("Failed to create socket\n");
}
// Bind Socket
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons((unsigned short) 4966);
if (bind(Handle,(struct sockaddr *) &address, sizeof(struct sockaddr_in))< 0){
printf("Failed to Bind\n");
}//end if
printf("Bind Done\n");
// Set to non Blocking
int NonBlocking = 1;
//if (fcntl(Handle, F_SETFL, O_NONBLOCK, NonBlocking) == -1){
printf("Faile to set nonblocking\n");
//}
Boolean ContinueLoop = true;
unsigned char Packet_Data[256];
unsigned int Maximum_Packet_Size = sizeof(Packet_Data);
struct sockaddr_in From_Address;
socklen_t FromLength = sizeof(From_Address);
while (ContinueLoop){
int Received_Bytes = recvfrom(Handle, (char *)Packet_Data, Maximum_Packet_Size, 0, (struct sockaddr *)&From_Address, &FromLength);
if (Received_Bytes > 0){
ContinueLoop = false;
printf("Got Data \n");
} else {
perror("Now");
printf(".");
}
close(Handle);
}//wend
Found the problem. I accidentally included the close statement inside the while loop. Moved it out of the loop where it belongs and all is working now. Blocking and nonblocking.

UDP broadcast using CFSocket on IOS

Have been doing some google search and some reading on this subject but cannot seem to get it right no matter how much time i spent searching.
What i want to do is to receive broadcast message of devices that are connected on my network by advertising my interest in their services that they supply. Using wireshark i can see the broadcast/notification messages from the network devices that i want to connect to sent over my network but not my broadcast search for interest of their services.
But with network utility i can see that the socket is created but don't know which state it is in, whether listen or connected.
Yes i know that there are libraries that i can use to do this, but i wanted to build something of my own from the ground up and get a better understand of how it works.
MySocket.h
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#if TARGET_OS_IPHONE
#import <CFNetwork/CFNetwork.h>
#endif
#interface MySocket : NSObject
{
NSString* _message;
CFSocketRef cfSocket;
CFRunLoopSourceRef cfSource;
}
- (void)listen;
#end
MySocket.m
#import "MySocket.h"
#define MAX_UDP_DATAGRAM_SIZE 65507
#implementation MySocket
static void socketCallback(CFSocketRef cfSocket, CFSocketCallBackType
type, CFDataRef address, const void *data, void *userInfo)
{
NSLog(#"socketCAllBAck was called");
}
- (void)listen
{
//Enable broadcast to network hosts
int yes = 1;
int setSockResult = 0;
_message = [[NSMutableString alloc ] initWithString: #"M-SEARCH *HTTP/1.1\r\nHOST:239.255.255.250:1900\r\nMAN:\"ssdp:discover\"\r\nST:ssdp:all\r\nMX:1\r\n\r\n"];
CFSocketContext socketContext = {0, self, NULL, NULL, NULL};
/* Create the server socket as a UDP IPv4 socket and set a callback */
/* for calls to the socket's lower-level accept() function */
cfSocket = CFSocketCreate(NULL, PF_INET, SOCK_DGRAM, IPPROTO_UDP,
kCFSocketAcceptCallBack | kCFSocketDataCallBack , (CFSocketCallBack)socketCallback, &socketContext);
if (cfSocket == NULL)
NSLog(#"UDP socket could not be created\n");
/* Re-use local addresses, if they're still in TIME_WAIT */
setSockResult = setsockopt(CFSocketGetNative(cfSocket), SOL_SOCKET, SO_BROADCAST, (void *)&yes, sizeof(yes));
if(setSockResult < 0)
NSLog(#"Could not setsockopt for broabcast");
/* Set the port and address we want to listen on */
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("239.255.255.250");
//inet_pton(AF_INET, "239.255.255.250", &(addr.sin_addr));
addr.sin_port = htons(1900);
//addr.sin_addr.s_addr = htonl(INADDR_ANY);
NSData *address = [ NSData dataWithBytes: &addr length: sizeof(addr) ];
if (address != nil && CFSocketSetAddress(cfSocket, (CFDataRef) address) != kCFSocketSuccess) {
NSLog(#"CFSocketSetAddress() failed\n");
CFRelease(cfSocket);
}
CFDataRef data = CFDataCreate(NULL, (const UInt8*)[_message UTF8String], [_message lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
setSockResult = CFSocketSendData(cfSocket, (CFDataRef)address, data, 0.0);
if(kCFSocketSuccess != setSockResult) NSLog(#"Unable to send data, %i", setSockResult);
else NSLog(#"Sending data");
cfSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, cfSocket, 0);
if(cfSource == NULL)
NSLog(#"CFRunLoopSourceRef is null");
CFRunLoopAddSource(CFRunLoopGetCurrent(), cfSource, kCFRunLoopDefaultMode);
NSLog(#"Socket listening on port 1900");
CFRelease(cfSource);
CFRelease(cfSocket);
[address release];
data = nil;
CFRunLoopRun();
}
- (void)dealloc
{
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), cfSource, kCFRunLoopDefaultMode);
CFRelease(cfSource);
CFRelease(cfSocket);
[_message release];
[super dealloc];
}
#end
Edit: Everything runs well until the call to send data.
Is there something small but critical in order for this to work that i'm missing?
Or i'm missing the big picture?
Any help or guide is appreciated.
Thanks in advance and have a nice weekend
remove SetAdress and all will be work fine. i've tested this now;
How about use this initialization with address
CFDataRef address=CFDataCreate(kCFAllocatorDefault,(UInt8 *)&addr,sizeof(addr));

Fail in release/Adhoc build But work in debug mode (ios)

Running a sample application in background mode(ios) using TCP sockets.It give message(a local notification ) when client send any message and wait for another message.It works fine when the application run in debugging, but crashes in release mode after 10 seconds.
used: xcode 4.2 & iPad 2 for testing..
This is the code I'm working with:
struct sockaddr_in serv_addr, cli_addr;
CFReadStreamRef hReadStream;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) printf("Sockfd Error\n");
bzero((char *) &serv_addr, sizeof(serv_addr));
portNo = 3600;//atoi(argv);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portNo);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
printf("bind error\n");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = 1;
while(newsockfd)
{
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
NSLog(#"newsockfd create %d\n",newsockfd);
remoteAdd = inet_ntoa(cli_addr.sin_addr);
//cout << remoteAdd << " port = " << cli_addr.sin_port << endl;
portNo = cli_addr.sin_port;
#if defined(__IPHONE_4_0) && !(TARGET_IPHONE_SIMULATOR)
NSLog(#"newsocket %d\n",newsockfd);
// Only do this if it is a SipSocket we are watching
if (newsockfd)
{
// Set it to non-blocking
//int set = 0;
//ioctl(newsockfd, FIONBIO, reinterpret_cast<int>(&set));
CFStreamCreatePairWithSocket (kCFAllocatorDefault, newsockfd,
&hReadStream, NULL);
if (CFReadStreamSetProperty(hReadStream,
kCFStreamNetworkServiceType,
kCFStreamNetworkServiceTypeVoIP) != TRUE)
{
// An error occured, delete the stream
if(hReadStream != NULL)
{
CFReadStreamClose(hReadStream);
CFRelease(hReadStream);
hReadStream = NULL;
}
//return -1;
}
else NSLog(#" >>>>>>>>>>>>>>>>>>> property set Here <<<<<<<<<<<<<<<<\n");
if (CFReadStreamOpen(hReadStream) != TRUE)
{
// An error occured, delete the stream
if(hReadStream != NULL)
{
CFReadStreamClose(hReadStream);
CFRelease(hReadStream);
hReadStream = NULL;
}
// return -1;
}
else NSLog(#"read....\n");
}
#endif
[self test];
}
Crash report in device log :
"Application 'Demo' exited abnormally with signal 9: Killed: 9" &
"unknown ReportCrash[10915] <Error>: Saved crashreport to
/var/mobile/Library/Logs/CrashReporter/servertest_2011-12-13-163920_EyeBalls-iPad.plist
using uid: 0 gid: 0, synthetic_euid: 501 egid: 0"
Trying to found the bug but it works fine in debug mode Exactly no error found in device log or debug window..Please help me :(
you can switch your compiler option to llvm gcc4.2 . I guess it issue related to clang.
hope it will work fine.

Resources