Socket with IOS cocos2dx - ios

I need to build an game use Socket to connect multi device.
I have a problem when i try to create socket on cocos2dx.
void AcceptCallBack(
CFSocketRef socket,
CFSocketCallBackType type,
CFDataRef address,
const void *data,
void *info)
{
CFReadStreamRef readStream = NULL;
CFWriteStreamRef writeStream = NULL;
CFIndex bytes;
UInt8 buffer[128];
UInt8 recv_len = 0, send_len = 0;
/* The native socket, used for various operations */
CFSocketNativeHandle sock = *(CFSocketNativeHandle *) data;
/* The punch line we stored in the socket context */
char *punchline = info;
/* Create the read and write streams for the socket */
CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock,
&readStream, &writeStream);
if (!readStream || !writeStream) {
close(sock);
fprintf(stderr, "CFStreamCreatePairWithSocket() failed\n");
return;
}
CFReadStreamOpen(readStream);
CFWriteStreamOpen(writeStream);
/* Wait for the client to finish sending the joke; wait for newline */
memset(buffer, 0, sizeof(buffer));
while (!strchr((char *) buffer, '\n') && recv_len < sizeof(buffer)) {
bytes = CFReadStreamRead(readStream, buffer + recv_len,
sizeof(buffer) - recv_len);
if (bytes < 0) {
// fprintf(stderr, "CFReadStreamRead() failed: %d\n", bytes);
close(sock);
return;
}
// NSLog(#"Read: %d", bytesRead);
NSLog(#"buffer: %s", buffer);
recv_len += bytes;
}
/* Send the punchline */
while (send_len < (strlen(punchline+1))) {
if (CFWriteStreamCanAcceptBytes(writeStream)) {
bytes = CFWriteStreamWrite(writeStream,
(unsigned char *) punchline + send_len,
(strlen((punchline)+1) - send_len) );
if (bytes < 0) {
fprintf(stderr, "CFWriteStreamWrite() failed\n");
close(sock);
return;
}
send_len += bytes;
}
close(sock);
CFReadStreamClose(readStream);
CFWriteStreamClose(writeStream);
return;
}
}
Everything is ok when i run it on Ios Application (Default setting by Xcode when create new project)
But when i copy that source code to project create by Cocos2dx.
I got an error at this line:
char *punchline = info;
Error message:
Can not initialize a variable of type 'char *' with an Ivalue of type 'void *'
I don't know which setting should be change to run it.
Thanks.

Related

LWIP threads seems to block any other threads on my FREERTOS setup on a arty Z7

I am learning freertos and lwip on a Arty Z7.
I have managed to launch several tasks without problem but when I try to setup a lwip server to receive TCP packets, the server works perfectly but the other tasks won't continue their work.
So when I run the following code, the xil_printf of the "dumb_task" is writing correctly its message until the PHY autonegation is complete. Then, Nothing will happen from the dumb_task but the connection from the tcp port are accepted by the fpga. (I have commented by purpose the receive packet thread as it's changing nothing).
Do you have any ideas of what could be the problem?
Thank you!
Here is my code:
what is in my main file:
static sys_thread_t g_server_th_handle;
void dumb_task(void *p){
while(1){
xil_printf("dummy!\n");
vTaskDelay(10);
}
}
int main()
{
xTaskCreate (dumb_task, "TestTask", 512, NULL, 4, NULL);
g_server_th_handle = create_server_thread(2);
vTaskStartScheduler();
while(1);
return 0;
}
what is in a .cpp/.h file for the server:
static sys_thread_t g_server_thread_handle;
static int complete_nw_thread;
struct netif server_netif;
int g_server_tasks_priority = DEFAULT_THREAD_PRIO;
void setting_thread(void *p)
{
/* the mac address of the board. this should be unique per board */
u8_t mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
/* Add network interface to the netif_list, and set it as default */
if (!xemac_add(&server_netif, NULL, NULL, NULL, mac_ethernet_address,
PLATFORM_EMAC_BASEADDR)) {
xil_printf("Error adding N/W interface\r\n");
return;
}
netif_set_default(&server_netif);
/* specify that the network if is up */
netif_set_up(&server_netif);
/* start packet receive thread - required for lwIP operation */
sys_thread_new("xemacif_input_thread",
(void(*)(void*))xemacif_input_thread, &server_netif,
THREAD_STACKSIZE, g_server_tasks_priority);
complete_nw_thread = 1;
vTaskResume(g_server_thread_handle);
vTaskDelete(NULL);
}
void accept_loop()
{
int sock, new_sd;
int opt=1;
struct sockaddr_in address, remote;
int size;
// set up address to connect to
memset(&address, 0, sizeof(address));
if ((sock = lwip_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
xil_printf("TCP server: Error creating Socket\r\n");
return;
}
address.sin_family = AF_INET;
address.sin_port = htons(TCP_CONN_PORT);
address.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0) {
xil_printf("TCP server: Unable to bind to port %d\r\n",
TCP_CONN_PORT);
close(sock);
return;
}
ioctl(sock,FIONBIO,&opt);
if (listen(sock, 0) < 0) {
xil_printf("TCP server: tcp_listen failed\r\n");
close(sock);
return;
}
size = sizeof(remote);
xil_printf("Server set and listening\n\r");
for(;;) {
if ((new_sd = accept(sock, (struct sockaddr *)&remote,
(socklen_t *)&size)) > 0){
char *ip = inet_ntoa(((struct sockaddr_in*) &remote)->sin_addr);
gTCP_connection_count +=1;
xil_printf("New connection from %s. Number of client : %d\n\r",
ip,gTCP_connection_count);
/*sys_thread_new("TCP_recv thread",
tcp_recv_traffic, (void*)&new_sd,
TCP_SERVER_THREAD_STACKSIZE,
g_server_tasks_priority);*/
}
vTaskDelay(pdMS_TO_TICKS( 1UL ));
}
}
void server_thread(void *p)
{
// /* initialize lwIP before calling sys_thread_new */
lwip_init();
/* any thread using lwIP should be created using sys_thread_new */
sys_thread_new("nw_thread", setting_thread, NULL,
THREAD_STACKSIZE, g_server_tasks_priority);
/* Suspend Task until auto-negotiation is completed */
if (!complete_nw_thread){
vTaskSuspend(NULL);
}
assign_default_ip(&(server_netif.ip_addr), &(server_netif.netmask),
&(server_netif.gw));
print_ip_settings(&(server_netif.ip_addr), &(server_netif.netmask),
&(server_netif.gw));
/* start the application*/
accept_loop();
vTaskDelete(NULL);
return;
}
sys_thread_t create_server_thread(int priority){
g_server_tasks_priority = priority;
g_server_thread_handle = sys_thread_new("server_thread", server_thread, 0,
THREAD_STACKSIZE, priority );
return g_server_thread_handle;
}

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.

Apps are reviewed on an IPv6 network. Please ensure that your app supports IPv6 networks, as IPv6 compatibility is required

I have received the following rejection from Apple for my app the last couple of days. My app communicates with UDP and the remote server is always IPv4. I have used BSD sockets. Please guide me how can I solve this problem.
I have tried to create a NAT64 hotspot using an IPv4 network but I was unable to send any packets to the server. Moreover, we don't have IPv6 available at my place now.
From Apple:
2.2 Details
We discovered one or more bugs in your app when reviewed on an iPad running iOS 9.3.2 and iPhone running iOS 9.3.2 on both Wi-Fi and cellular networks.
Specifically, during review we were unable to bypass the Initializing page. We encountered an error while waiting for the app to load. We've attached a screenshot for your reference.
Next Steps
Please run your app on a device to identify the issue(s), then revise and resubmit your app for review.
Apps are reviewed on an IPv6 network. Please ensure that your app supports IPv6 networks, as IPv6 compatibility is required.
For additional information about supporting IPv6 Networks, please refer to Supporting iPv6 DNS64/NAT64 Networks.
Source Code Bellow:
UdpSocketManager.h >>
#ifndef UDP_SOCKET_MANAGER_H__
#define UDP_SOCKET_MANAGER_H__
#import "TInetAddr.h"
class UdpSocketManager
{
public:
UdpSocketManager();
~UdpSocketManager();
void getLocalAddress();
void initializeSocket();
void start();
void stop();
void sendSignal(int p_type, TInetAddr *p_destAddress, unsigned char *p_data, int p_length);
void receiveSignal();
int localPort;
int signalingSocket;
int signalSocketRecvLength;
int socketFamily;
int isIPV4Available;
int isIPV6Available;
char wifiIP[INET_ADDRSTRLEN];
char cellularIP[INET_ADDRSTRLEN];
char wifiIP_v6[INET6_ADDRSTRLEN];
char cellularIP_v6[INET6_ADDRSTRLEN];
long returnLength;
struct sockaddr_in remoteAddrForRecv;
struct sockaddr_in srcAddrV4;
struct sockaddr_in6 srcAddrV6;
struct sockaddr_in sendAddr4;
struct sockaddr_in6 sendAddr6;
bool running;
pthread_t thread;
};
#endif
UdpSocketManager.m >>
#include <string.h>
#include <pthread.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "UdpSocketManager.h"
#import <Foundation/Foundation.h>
unsigned int ipAddressToUnsignedInt(char *ipAddress)
{
unsigned int ipAddressLongValue = 0L;
int byteSegment = 0;
for(int i = 0; i < strlen(ipAddress); i++)
{
char ch = ipAddress[i];
if(ch == '.')
{
ipAddressLongValue <<= 8;
ipAddressLongValue |= byteSegment;
byteSegment = 0;
}
else
{
byteSegment = byteSegment * 10 + (ch - 48);
}
}
ipAddressLongValue <<= 8;
ipAddressLongValue |= byteSegment;
return ipAddressLongValue;
}
int custom_random(int max=65535)
{
int randomValue;
randomValue = arc4random_uniform(65535)%max;
return randomValue;
}
int custom_random(int min, int max)
{
int randomValue;
randomValue = arc4random_uniform(max);
if(randomValue<min)
randomValue=(min+custom_random(max-min));
return randomValue;
}
void* runUdpSocketManager(void *objRef)
{
UdpSocketManager *THIS = (UdpSocketManager *) objRef;
THIS->running=true;
while (THIS->running)
{
THIS->receiveSignal();
}
pthread_exit(NULL);
return 0;
}
UdpSocketManager::UdpSocketManager()
{
socketFamily=AF_INET;
signalingSocket=-1;
running=false;
initializeSocket();
}
UdpSocketManager::~UdpSocketManager()
{
}
void UdpSocketManager::getLocalAddress()
{
//Read local address
getLocalAddress();
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success=0;
isIPV4Available=FALSE;
isIPV6Available=FALSE;
success = getifaddrs(&interfaces);
if (success == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL)
{
if(temp_addr->ifa_addr->sa_family==AF_INET)
{
if([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:#"en"])
{
isIPV4Available=TRUE;
strcpy(wifiIP, inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
printf("IP Address: %s\n",inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
}
else if([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:#"pdp_ip0"])
{
isIPV4Available=TRUE;
strcpy(cellularIP, inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
printf("IP Address: %s\n",inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
}
}
else if(temp_addr->ifa_addr->sa_family==AF_INET6)
{
if([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:#"en"])
{
isIPV6Available=TRUE;
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr), (char*)wifiIP_v6, INET6_ADDRSTRLEN);
printf("Interface: %s IPV6: %s\n",temp_addr->ifa_name,wifiIP_v6);
}
else if([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:#"pdp_ip0"])
{
isIPV6Available=TRUE;
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr), (char*)cellularIP_v6, INET6_ADDRSTRLEN);
printf("Interface: %s IPV6: %s\n",temp_addr->ifa_name,cellularIP_v6);
}
}
temp_addr = temp_addr->ifa_next;
}
}
freeifaddrs(interfaces);
}
void UdpSocketManager::initializeSocket()
{
if(signalingSocket!=-1)
close(signalingSocket);
if (isIPV4Available)
{
if((signalingSocket=socket(AF_INET, SOCK_DGRAM, 0))==-1)
{
NSLog(#"Unable to create signaling socket of AF_INET");
}
else
{
socketFamily=AF_INET;
NSLog(#"Socket created successfully. [AF_INET]");
}
}
else if(!isIPV4Available && isIPV6Available)
{
if((signalingSocket=socket(AF_INET6, SOCK_DGRAM, 0))==-1)
{
NSLog(#"Unable to create signaling socket of AF_INET6");
}
else
{
socketFamily=AF_INET6;
NSLog(#"Socket created successfully. [AF_INET6]");
}
}
else
{
if((signalingSocket=socket(AF_INET, SOCK_DGRAM, 0))==-1)
{
NSLog(#"Unable to create signaling socket of AF_INET");
}
else
{
socketFamily=AF_INET;
NSLog(#"Socket created successfully. [AF_INET]");
}
}
int count=0;
while(true)
{
count++;
if(socketFamily==AF_INET)
{
srcAddrV4.sin_len = sizeof(srcAddrV4);
srcAddrV4.sin_family = socketFamily;
srcAddrV4.sin_addr.s_addr = INADDR_ANY;
srcAddrV4.sin_port = htons(localPort);
if (bind(signalingSocket, (struct sockaddr *) &srcAddrV4, sizeof(srcAddrV4)) < 0)
{
NSLog(#"[AF_INET] ERROR occured creating signaling port at attempt (%d) Port: %d", count, localPort);
localPort=(int)custom_random(1024, 65535);
}
else
{
int on=1;
setsockopt(signalingSocket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
setsockopt(signalingSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
NSLog(#"[AF_INET] SignalingSocket Created Successfully at attempt (%d) Port: %d\n", count, localPort);
break;
}
}
else
{
srcAddrV6.sin6_len = sizeof(srcAddrV6);
srcAddrV6.sin6_family = socketFamily;
srcAddrV6.sin6_addr = in6addr_any;
srcAddrV6.sin6_port = htons(localPort);
if (bind(signalingSocket, (struct sockaddr *) &srcAddrV6, sizeof(srcAddrV6)) < 0)
{
NSLog(#"[AF_INET] ERROR occured creating signaling port at attempt (%d) Port: %d", count, localPort);
localPort=(int)custom_random(1024, 65535);
}
else
{
int on=1;
setsockopt(signalingSocket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&on, sizeof(on));
setsockopt(signalingSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
NSLog(#"[AF_INET6] SignalingSocket Created Successfully at attempt (%d) Port: %d\n", count, localPort);
break;
}
}
}
}
void UdpSocketManager::start()
{
pthread_create(&thread, NULL, runUdpSocketManager, (void *) this);
}
void UdpSocketManager::stop()
{
running=false;
}
void UdpSocketManager::receiveSignal()
{
int port;
char ipAddress[16];
socklen_t fromlen;
unsigned char udpSignalRecvBuffer[1600];
fromlen = sizeof(remoteAddrForRecv);
signalSocketRecvLength = (int)recvfrom(signalingSocket, (char *)udpSignalRecvBuffer,1600,0,(struct sockaddr *)&remoteAddrForRecv,&fromlen);
if(signalSocketRecvLength>0)
{
strcpy(ipAddress, inet_ntoa(remoteAddrForRecv.sin_addr));
port = ntohs(remoteAddrForRecv.sin_port);
NSLog(#"RECEIVED %d bytes from %s:%d", signalSocketRecvLength, ipAddress, port);
}
else
{
usleep(10000);// 10 ms
}
}
void UdpSocketManager::sendSignal(int p_type, TInetAddr *p_destAddress, unsigned char *p_data, int p_length)
{
if(socketFamily==AF_INET6)
{
// Convert IPv4 address to IPv4-mapped-into-IPv6 address.
sendAddr6.sin6_family = AF_INET6;
sendAddr6.sin6_port = p_destAddress->m_port;
sendAddr6.sin6_addr.__u6_addr.__u6_addr32[0] = 0;
sendAddr6.sin6_addr.__u6_addr.__u6_addr32[1] = 0;
sendAddr6.sin6_addr.__u6_addr.__u6_addr32[2] = htonl(0xffff);
sendAddr6.sin6_addr.__u6_addr.__u6_addr32[3] = ntohl(ipAddressToUnsignedInt(p_destAddress->m_address));
sendAddr6.sin6_addr.__u6_addr.__u6_addr16[4] = 0;
sendAddr6.sin6_addr.__u6_addr.__u6_addr16[5] = 0xffff;
char ipV6Address[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &sendAddr6.sin6_addr, ipV6Address, INET6_ADDRSTRLEN);
NSLog(#"ipV6Address: %s\n", ipV6Address);
sendAddr6.sin6_flowinfo = 0;
sendAddr6.sin6_scope_id = 0;
}
else
{
sendAddr4.sin_family = AF_INET;
sendAddr4.sin_port = htons(p_destAddress->m_port);
if(inet_aton((char *) p_destAddress->m_address, &sendAddr4.sin_addr)==0)
{
NSLog(#"signal message - inet_aton() failed, %s", p_destAddress->m_address);
}
}
if(socketFamily==AF_INET)
returnLength=sendto(signalingSocket, p_data, p_length, 0, (struct sockaddr *)&sendAddr4, sizeof(sendAddr4));
else
returnLength=sendto(signalingSocket, p_data, p_length, 0, (struct sockaddr *)&sendAddr6, sizeof(sendAddr6));
NSLog(#"SENT %ld bytes to %s:%d\n", returnLength,p_destAddress->m_address,p_destAddress->m_port);
}
I don't think your "Convert IPv4 address to IPv4-mapped-into-IPv6 address" is correct. Rather than trying to construct an address yourself, you should call getaddrinfo() with a string of the thing you want to connect to (which could be either a hostname or an IPv4 address literal), and it will return to you a list of sockaddrs; you should use the first one from there to pass to sendto. It will give you the appropriate IP address family to use, and if you give an IPv4 address and it is an IPv6-only network (without you having to test anything), it will automatically give you the correct IPv6 address to use for that NAT64 router (without you needing to figure this out yourself). (If you wanted to manually construct an IPv6 address from IPv4 using NAT64/DNS64 without using getaddrinfo(), you would have to follow the complicated procedure in RFC 7050.)
Also, all the things you are doing in getLocalAddress() is unnecessary and potentially leads to more problems. You don't need isIPV4Available or isIPV6Available -- you shouldn't care at that point. Just create and bind both an IPv4 and an IPv6 socket in the beginning (not needing to care which one works), and each time you need to send, you get the right sockaddr to use using getaddrinfo() as above, and then send to the socket whose address family corresponds to the sockaddr you are using. And when you want to receive, you call recvfrom on both sockets.
I see several problems with the code you have shown:
UdpSocketManager does not call getLocalAddress() before calling initializeSocket(), so the binding socket is always IPv4, never IPv6. You are also not initializing localPort before calling initializeSocket(), either.
getLocalAddress() (if ever called) calls itself, so you have an endless recursion loop.
The use of custom_random() in a loop to pick a random binding port is just plain wrong, unnecessary, and potentially unending. To pick a random port when your configured port fails, just call bind() one time with the port set to 0. The OS knows which ports are available and will pick an available random port for you. Your entire initializeSocket() is overly complicated for what it attempts to do. It can be greatly simplified.
When enabling SO_REUSEADDR, it must be enabled before calling bind(), not after. Also look at SO_REUSEPORT.
Your remoteAddrForRecv variable is declared as sockaddr_in, which is only large enough to hold an IPv4 address and will cause recvfrom() to fail if called on an IPv6 socket. Use sockaddr_storage instead. In fact. All of your sockaddr_in and sockaddr_in6 variables should be replaced with sockaddr_storage.
inet_ntoa() is likewise also IPv4-only. Use inet_ntop() instead to handle both IPv4 and IPv6 addresses.
Try something more like this instead:
UdpSocketManager.h
#ifndef UDP_SOCKET_MANAGER_H__
#define UDP_SOCKET_MANAGER_H__
#import "TInetAddr.h"
class UdpSocketManager
{
public:
UdpSocketManager();
~UdpSocketManager();
void getLocalAddresses();
void initializeSocket();
void start();
void stop();
void sendSignal(int p_type, TInetAddr *p_destAddress, unsigned char *p_data, int p_length);
void receiveSignal();
int localPort;
int signalingSocket;
int socketFamily;
int isIPV4Available;
int isIPV6Available;
char wifiIP_v4[INET_ADDRSTRLEN];
char cellularIP_v4[INET_ADDRSTRLEN];
char wifiIP_v6[INET6_ADDRSTRLEN];
char cellularIP_v6[INET6_ADDRSTRLEN];
bool running;
pthread_t thread;
};
#endif
UdpSocketManager.m
#include <string.h>
#include <pthread.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "UdpSocketManager.h"
#import <Foundation/Foundation.h>
void* runUdpSocketManager(void *objRef)
{
UdpSocketManager *THIS = (UdpSocketManager *) objRef;
while (THIS->running)
{
THIS->receiveSignal();
}
pthread_exit(NULL);
return 0;
}
UdpSocketManager::UdpSocketManager()
{
socketFamily = AF_INET;
signalingSocket = -1;
localPort = 0; // or whatever port you actual want
srcAddrLen = 0;
sendAddrLen = 0;
running = false;
initializeSocket();
}
UdpSocketManager::~UdpSocketManager()
{
if(signalingSocket != -1)
{
close(signalingSocket);
signalingSocket = -1;
}
}
void UdpSocketManager::getLocalAddresses()
{
//Read local addresses
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
isIPV4Available = FALSE;
isIPV6Available = FALSE;
memset(&wifiIP_v4, 0, sizeof(wifiIP_v4));
memset(&cellularIP_v4, 0, sizeof(cellularIP_v4));
memset(&wifiIP_v6, 0, sizeof(wifiIP_v6));
memset(&cellularIP_v6, 0, sizeof(cellularIP_v6));
if(getifaddrs(&interfaces) == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL)
{
if ([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:#"en"])
{
if(temp_addr->ifa_addr->sa_family == AF_INET)
{
isIPV4Available = TRUE;
inet_ntop(AF_INET, &(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr), wifiIP_v4, sizeof(wifiIP_v4));
printf("Interface: %s IPv4: %s\n", temp_addr->ifa_name, wifiIP_v4);
}
else if(temp_addr->ifa_addr->sa_family == AF_INET6)
{
isIPV6Available = TRUE;
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr), wifiIP_v6, sizeof(wifiIP_v6));
printf("Interface: %s IPv6: %s\n", temp_addr->ifa_name, wifiIP_v6);
}
}
else if([[NSString stringWithUTF8String:temp_addr->ifa_name] hasPrefix:#"pdp_ip0"])
{
if(temp_addr->ifa_addr->sa_family == AF_INET)
{
isIPV4Available = TRUE;
inet_ntop(AF_INET, &(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr), cellularIP_v4, sizeof(cellularIP_v4));
printf("Interface: %s IPv6: %s\n", temp_addr->ifa_name, cellularIP_v4);
}
else if(temp_addr->ifa_addr->sa_family == AF_INET6)
{
isIPV6Available = TRUE;
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr), cellularIP_v6, sizeof(cellularIP_v6));
printf("Interface: %s IPv6: %s\n", temp_addr->ifa_name, cellularIP_v6);
}
}
temp_addr = temp_addr->ifa_next;
}
freeifaddrs(interfaces);
}
}
void UdpSocketManager::initializeSocket()
{
struct sockaddr_storage srcAddr;
struct sockaddr_in6 *srcAddr6;
struct sockaddr_in *srcAddr4;
socklen_t srcAddrLen;
if(signalingSocket != -1)
{
close(signalingSocket);
signalingSocket = -1;
}
getLocalAddresses();
if(isIPV6Available)
{
signalingSocket = socket(AF_INET6, SOCK_DGRAM, 0);
if(signalingSocket == -1)
{
NSLog(#"Unable to create IPv6 signaling socket");
return;
}
socketFamily = AF_INET6;
NSLog(#"IPv6 Socket created successfully");
}
else
{
signalingSocket = socket(AF_INET, SOCK_DGRAM, 0);
if(signalingSocket == -1)
{
NSLog(#"Unable to create IPv4 signaling socket");
return;
}
socketFamily = AF_INET;
NSLog(#"IPv4 Socket created successfully");
}
int on = 1;
setsockopt(signalingSocket, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
setsockopt(signalingSocket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if(socketFamily == AF_INET6)
{
on = 0;
setsockopt(signalingSocket, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
srcAddr6 = (struct sockaddr_in6 *) &srcAddr;
srcAddrLen = sizeof(sockaddr_in6);
srcAddr6->sin6_len = srcAddrLen;
srcAddr6->sin6_family = socketFamily;
srcAddr6->sin6_addr = in6addr_any;
srcAddr6->sin6_port = htons(localPort);
}
else
{
srcAddr4 = (struct sockaddr_in *) &srcAddr;
srcAddrLen = sizeof(sockaddr_in);
srcAddr4->sin_len = srcAddrLen;
srcAddr4->sin_family = socketFamily;
srcAddr4->sin_addr.s_addr = INADDR_ANY;
srcAddr4->sin_port = htons(localPort);
}
if (bind(signalingSocket, (struct sockaddr *) &srcAddr, srcAddrLen) < 0)
{
if (localPort == 0)
{
NSLog(#"ERROR occured binding random signaling port");
close(signalingSocket);
signalingSocket = -1;
return;
}
NSLog(#"ERROR occured binding signaling port: %d", localPort);
if(socketFamily == AF_INET6)
srcAddr6->sin6_port = 0;
else
srcAddr4->sin_port = 0;
if (bind(signalingSocket, (struct sockaddr *) &srcAddr, srcAddrLen) < 0)
{
NSLog(#"ERROR occured binding random signaling port");
close(signalingSocket);
signalingSocket = -1;
return;
}
getsockname(signalingSocket, (struct sockaddr *) &srcAddr, &srcAddrLen);
if(socketFamily == AF_INET6)
localPort = ntohs(srcAddr6->sin6_port);
else
localPort = ntohs(srcAddr4->sin_port);
}
NSLog(#"SignalingSocket bound successfully on Port: %d\n", localPort);
}
void UdpSocketManager::start()
{
if(signalingSocket != -1)
{
running = true;
pthread_create(&thread, NULL, runUdpSocketManager, this);
}
}
void UdpSocketManager::stop()
{
running = false;
}
void UdpSocketManager::receiveSignal()
{
int port;
char ipAddress[INET6_ADDRSTRLEN];
unsigned char udpSignalRecvBuffer[1600];
ssize_t signalRecvLength;
struct sockaddr_storage remoteAddr;
socklen_t fromlen;
fromlen = sizeof(remoteAddr);
signalRecvLength = recvfrom(signalingSocket, udpSignalRecvBuffer, sizeof(udpSignalRecvBuffer), 0, (struct sockaddr *) &remoteAddr, &fromlen);
if(signalRecvLength >= 0)
{
if(remoteAddrForRecv.ss_family == AF_INET6)
{
struct sockaddr_in6 *remoteAddr6 = (struct sockaddr_in6 *) &remoteAddr;
inet_ntop(AF_INET6, &(remoteAddr6->sin6_addr), ipAddress, sizeof(ipAddress));
port = ntohs(remoteAddr6->sin6_port);
}
else
{
struct sockaddr_in *remoteAddr4 = (struct sockaddr_in4 *) &remoteAddr;
inet_ntop(AF_INET, &(remoteAddr4->sin_addr), ipAddress, sizeof(ipAddress));
port = ntohs(remoteAddr4->sin_port);
}
NSLog(#"RECEIVED %d bytes from %s:%d", signalRecvLength, ipAddress, port);
}
else
{
usleep(10000);// 10 ms
}
}
void UdpSocketManager::sendSignal(int p_type, TInetAddr *p_destAddress, unsigned char *p_data, int p_length)
{
struct sockaddr_storage sendAddr;
socklen_t sendAddrLen;
ssize_t returnLength;
char ipAddress[INET6_ADDRSTRLEN];
if(socketFamily == AF_INET6)
{
struct sockaddr_in6 *sendAddr6 = (struct sockaddr_in6 *) &sendAddr;
sendAddrLen = sizeof(sockaddr_in6);
sendAddr6->sin6_family = AF_INET6;
sendAddr6->sin6_port = htons(p_destAddress->m_port);
// Convert IPv4 address to IPv4-mapped IPv6 address.
sendAddr6->sin6_addr.__u6_addr.__u6_addr32[0] = 0;
sendAddr6->sin6_addr.__u6_addr.__u6_addr32[1] = 0;
sendAddr6->sin6_addr.__u6_addr.__u6_addr16[4] = 0;
sendAddr6->sin6_addr.__u6_addr.__u6_addr16[5] = 0xffff;
sendAddr6->sin6_addr.__u6_addr.__u6_addr32[3] = inet_addr(p_destAddress->m_address);
sendAddr6->sin6_flowinfo = 0;
sendAddr6->sin6_scope_id = 0;
inet_ntop(AF_INET6, &(sendAddr6->sin6_addr), ipAddress, sizeof(ipAddress));
}
else
{
struct sockaddr_in *sendAddr4 = (struct sockaddr_in *) &sendAddr;
sendAddrLen = sizeof(sockaddr_in);
sendAddr4->sin_family = AF_INET;
sendAddr4->sin_port = htons(p_destAddress->m_port);
if(inet_aton((char *) p_destAddress->m_address, &(sendAddr4->sin_addr)) == 0)
{
NSLog(#"signal message - inet_aton() failed, %s", p_destAddress->m_address);
return;
}
inet_ntop(AF_INET, &(sendAddr4->sin_addr), ipAddress, sizeof(ipAddress));
}
returnLength = sendto(signalingSocket, p_data, p_length, 0, (struct sockaddr *) &sendAddr, sendAddrLen);
if(returnLength >= 0)
NSLog(#"SENT %ld bytes to %s:%d\n", returnLength, ipAddress, p_destAddress->m_port);
}
Solution for AFNetworking for reachability in IPv6 and IPv4
change the following code in class AFNetworkReachabilityManager
+ (instancetype)sharedManager {
static AFNetworkReachabilityManager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
struct sockaddr_in6 address;
bzero(&address, sizeof(address));
address.sin6_len = sizeof(address);
address.sin6_family = AF_INET6;
_sharedManager = [self managerForAddress:&address];
});
return _sharedManager;
}

iOS CFSocket crash on empty UDP packet

I am using a CFSocket configured for UDP to send data through wifi. The problem is that when I receive an empty UDP packet, the wifi suddenly stops working. I cant receive or send wnything anymore after that. Does anyone know what seems to be the problem? Here is my configuration and callback code:
void socketCallback(CFSocketRef cfSocket, CFSocketCallBackType type, CFDataRef address, const void *data, void *userInfo)
{
NSData * inputData = (__bridge NSData*)data;
NSUInteger inputDataCapacity = inputData.length * 2;
if(inputDataCapacity > minimalFrameSize*2){
//DO STH
}
}
-(void) initNetworkCommunication
{
CFSocketContext socketContext = {0, (__bridge void *)(self), NULL, NULL, NULL};
_cfSocket = CFSocketCreate(kCFAllocatorDefault, AF_INET, SOCK_DGRAM, IPPROTO_UDP, kCFSocketAcceptCallBack | kCFSocketDataCallBack, (CFSocketCallBack)socketCallback, &socketContext);
if ( _cfSocket == NULL) {
// NSLog(#"CfSocketCreate failed");
}
else {
if( _cfSocket ) {
_addrData = [Utils createIpAddressDataRef:COMM_INT_LISTENER_ADDR];
int flag = 1;
CFSocketNativeHandle socket_handle = (CFSocketNativeHandle)CFSocketGetNative(_cfSocket);
setsockopt(socket_handle, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag));
//set address of the socket to listen to
CFSocketSetAddress (_cfSocket, _addrData);
_cfSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _cfSocket, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), _cfSource, kCFRunLoopDefaultMode);
CFRelease(_cfSource);
CFRelease(_cfSocket);
}
}
}
And sometimes after the wifi "crash" happens, I get an "EXC_BAD_ACCESS" when using CFSocketSendData.

clicking/tapping between buffers for AudioQueue

As you can see from the code, within my callback I extract out the audio data and place it into NSData data, then send that off to another class to upload that to the server. This all works, meaning the server receives and plays the audio data. HOWEVER there is a clicking or tapping noise between the buffers. I am hoping someone might show me what is causing that and how it can be fixed.
I have read other related postings however they all seemed to refer to only using 1 buffer and that adding more was the fix but I am using 3 buffers and have tried adjusting that number which did not fix it
AQRecorder.mm
#include "AQRecorder.h"
RestClient * restClient;
NSData* data;
// ____________________________________________________________________________________
// Determine the size, in bytes, of a buffer necessary to represent the supplied number
// of seconds of audio data.
int AQRecorder::ComputeRecordBufferSize(const AudioStreamBasicDescription *format, float seconds)
{
int packets, frames, bytes = 0;
try {
frames = (int)ceil(seconds * format->mSampleRate);
if (format->mBytesPerFrame > 0)
bytes = frames * format->mBytesPerFrame;
else {
UInt32 maxPacketSize;
if (format->mBytesPerPacket > 0)
maxPacketSize = format->mBytesPerPacket; // constant packet size
else {
UInt32 propertySize = sizeof(maxPacketSize);
XThrowIfError(AudioQueueGetProperty(mQueue, kAudioQueueProperty_MaximumOutputPacketSize, &maxPacketSize,
&propertySize), "couldn't get queue's maximum output packet size");
}
if (format->mFramesPerPacket > 0)
packets = frames / format->mFramesPerPacket;
else
packets = frames; // worst-case scenario: 1 frame in a packet
if (packets == 0) // sanity check
packets = 1;
bytes = packets * maxPacketSize;
}
} catch (CAXException e) {
char buf[256];
fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
return 0;
}
return bytes;
}
// ____________________________________________________________________________________
// AudioQueue callback function, called when an input buffers has been filled.
void AQRecorder::MyInputBufferHandler( void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp * inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription* inPacketDesc)
{
AQRecorder *aqr = (AQRecorder *)inUserData;
try {
if (inNumPackets > 0) {
// write packets to file
// XThrowIfError(AudioFileWritePackets(aqr->mRecordFile, FALSE, inBuffer->mAudioDataByteSize,
// inPacketDesc, aqr->mRecordPacket, &inNumPackets, inBuffer->mAudioData),
// "AudioFileWritePackets failed");
aqr->mRecordPacket += inNumPackets;
// int numBytes = inBuffer->mAudioDataByteSize;
// SInt8 *testBuffer = (SInt8*)inBuffer->mAudioData;
//
// for (int i=0; i < numBytes; i++)
// {
// SInt8 currentData = testBuffer[i];
// printf("Current data in testbuffer is %d", currentData);
//
// NSData * temp = [NSData dataWithBytes:currentData length:sizeof(currentData)];
// }
data=[[NSData dataWithBytes:inBuffer->mAudioData length:inBuffer->mAudioDataByteSize]retain];
[restClient uploadAudioData:data url:nil];
}
// if we're not stopping, re-enqueue the buffer so that it gets filled again
if (aqr->IsRunning())
XThrowIfError(AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL), "AudioQueueEnqueueBuffer failed");
} catch (CAXException e) {
char buf[256];
fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
}
AQRecorder::AQRecorder()
{
mIsRunning = false;
mRecordPacket = 0;
data = [[NSData alloc]init];
restClient = [[RestClient sharedManager]retain];
}
AQRecorder::~AQRecorder()
{
AudioQueueDispose(mQueue, TRUE);
AudioFileClose(mRecordFile);
if (mFileName){
CFRelease(mFileName);
}
[restClient release];
[data release];
}
// ____________________________________________________________________________________
// Copy a queue's encoder's magic cookie to an audio file.
void AQRecorder::CopyEncoderCookieToFile()
{
UInt32 propertySize;
// get the magic cookie, if any, from the converter
OSStatus err = AudioQueueGetPropertySize(mQueue, kAudioQueueProperty_MagicCookie, &propertySize);
// we can get a noErr result and also a propertySize == 0
// -- if the file format does support magic cookies, but this file doesn't have one.
if (err == noErr && propertySize > 0) {
Byte *magicCookie = new Byte[propertySize];
UInt32 magicCookieSize;
XThrowIfError(AudioQueueGetProperty(mQueue, kAudioQueueProperty_MagicCookie, magicCookie, &propertySize), "get audio converter's magic cookie");
magicCookieSize = propertySize; // the converter lies and tell us the wrong size
// now set the magic cookie on the output file
UInt32 willEatTheCookie = false;
// the converter wants to give us one; will the file take it?
err = AudioFileGetPropertyInfo(mRecordFile, kAudioFilePropertyMagicCookieData, NULL, &willEatTheCookie);
if (err == noErr && willEatTheCookie) {
err = AudioFileSetProperty(mRecordFile, kAudioFilePropertyMagicCookieData, magicCookieSize, magicCookie);
XThrowIfError(err, "set audio file's magic cookie");
}
delete[] magicCookie;
}
}
void AQRecorder::SetupAudioFormat(UInt32 inFormatID)
{
memset(&mRecordFormat, 0, sizeof(mRecordFormat));
UInt32 size = sizeof(mRecordFormat.mSampleRate);
XThrowIfError(AudioSessionGetProperty( kAudioSessionProperty_CurrentHardwareSampleRate,
&size,
&mRecordFormat.mSampleRate), "couldn't get hardware sample rate");
//override samplearate to 8k from device sample rate
mRecordFormat.mSampleRate = 8000.0;
size = sizeof(mRecordFormat.mChannelsPerFrame);
XThrowIfError(AudioSessionGetProperty( kAudioSessionProperty_CurrentHardwareInputNumberChannels,
&size,
&mRecordFormat.mChannelsPerFrame), "couldn't get input channel count");
// mRecordFormat.mChannelsPerFrame = 1;
mRecordFormat.mFormatID = inFormatID;
if (inFormatID == kAudioFormatLinearPCM)
{
// if we want pcm, default to signed 16-bit little-endian
mRecordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
mRecordFormat.mBitsPerChannel = 16;
mRecordFormat.mBytesPerPacket = mRecordFormat.mBytesPerFrame = (mRecordFormat.mBitsPerChannel / 8) * mRecordFormat.mChannelsPerFrame;
mRecordFormat.mFramesPerPacket = 1;
}
if (inFormatID == kAudioFormatULaw) {
NSLog(#"is ulaw");
mRecordFormat.mSampleRate = 8000.0;
mRecordFormat.mFormatFlags = 0;
mRecordFormat.mFramesPerPacket = 1;
mRecordFormat.mChannelsPerFrame = 1;
mRecordFormat.mBitsPerChannel = 8;
mRecordFormat.mBytesPerPacket = 1;
mRecordFormat.mBytesPerFrame = 1;
}
}
NSString * GetDocumentDirectory(void)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
void AQRecorder::StartRecord(CFStringRef inRecordFile)
{
int i, bufferByteSize;
UInt32 size;
CFURLRef url;
try {
mFileName = CFStringCreateCopy(kCFAllocatorDefault, inRecordFile);
// specify the recording format
SetupAudioFormat(kAudioFormatULaw /*kAudioFormatLinearPCM*/);
// create the queue
XThrowIfError(AudioQueueNewInput(
&mRecordFormat,
MyInputBufferHandler,
this /* userData */,
NULL /* run loop */, NULL /* run loop mode */,
0 /* flags */, &mQueue), "AudioQueueNewInput failed");
// get the record format back from the queue's audio converter --
// the file may require a more specific stream description than was necessary to create the encoder.
mRecordPacket = 0;
size = sizeof(mRecordFormat);
XThrowIfError(AudioQueueGetProperty(mQueue, kAudioQueueProperty_StreamDescription,
&mRecordFormat, &size), "couldn't get queue's format");
NSString *basePath = GetDocumentDirectory();
NSString *recordFile = [basePath /*NSTemporaryDirectory()*/ stringByAppendingPathComponent: (NSString*)inRecordFile];
url = CFURLCreateWithString(kCFAllocatorDefault, (CFStringRef)recordFile, NULL);
// create the audio file
XThrowIfError(AudioFileCreateWithURL(url, kAudioFileCAFType, &mRecordFormat, kAudioFileFlags_EraseFile,
&mRecordFile), "AudioFileCreateWithURL failed");
CFRelease(url);
// copy the cookie first to give the file object as much info as we can about the data going in
// not necessary for pcm, but required for some compressed audio
CopyEncoderCookieToFile();
// allocate and enqueue buffers
bufferByteSize = ComputeRecordBufferSize(&mRecordFormat, kBufferDurationSeconds); // enough bytes for half a second
for (i = 0; i < kNumberRecordBuffers; ++i) {
XThrowIfError(AudioQueueAllocateBuffer(mQueue, bufferByteSize, &mBuffers[i]),
"AudioQueueAllocateBuffer failed");
XThrowIfError(AudioQueueEnqueueBuffer(mQueue, mBuffers[i], 0, NULL),
"AudioQueueEnqueueBuffer failed");
}
// start the queue
mIsRunning = true;
XThrowIfError(AudioQueueStart(mQueue, NULL), "AudioQueueStart failed");
}
catch (CAXException &e) {
char buf[256];
fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
catch (...) {
fprintf(stderr, "An unknown error occurred\n");
}
}
void AQRecorder::StopRecord()
{
// end recording
mIsRunning = false;
// XThrowIfError(AudioQueueReset(mQueue), "AudioQueueStop failed");
XThrowIfError(AudioQueueStop(mQueue, true), "AudioQueueStop failed");
// a codec may update its cookie at the end of an encoding session, so reapply it to the file now
CopyEncoderCookieToFile();
if (mFileName)
{
CFRelease(mFileName);
mFileName = NULL;
}
AudioQueueDispose(mQueue, true);
AudioFileClose(mRecordFile);
}
I changed my #define kBufferDurationSeconds from .5 to 5.0 and although the clicking is still there it is alot less noticeable.
Please if you have suggestions/answer still post as this is not a fix merely a work around thats somewhat better then before
I also tried to append data to data for a number of times prior to sending the data to the server. This also seems to have helped.

Resources