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

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

Related

How to send a chunk of data using shlib(nghttp2) in esp32?

I want to use HTTP2 to POST data continuously. As I found, the only feasible solution is to use shlib. I can implement it and use it. But there were two problems that I faced:
1- shlib does not let us send a data bigger than 16KB theoretically. Here, the solution that I found was to feed the buffer couple of times without calling NGHTTP2_DATA_FLAG_EOF. But, the main problem is that we cannot return the size of the buffer which although is defined as int, but does not support lengths more than 16K.
2- The fault rate of sending data more than about 3 to 4K goes exponentially high as in these situations, just a few of packets are able to be sent correctly.
Any suggestion?
Thanks
I did all my bests to make sure that the resources don't interfere with each other. Here is my code:
#include <Arduino.h>
#include <WiFiClientSecure.h>
#include "esp_camera.h"
extern "C"
{
#include "sh2lib.h"
}
#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif
// CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
const char* ssid = "NETWORK"; // your network SSID (name of wifi network)
const char* password = "PASSWORD"; // your network password
bool request_finished = false;
String head = "--JPEG_IMAGE\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n--JPEG_IMAGE--\r\n";
char data_to_post[16000];
uint32_t totalLen;
camera_config_t config;
struct sh2lib_handle hd;
bool is_captured;
bool is_posted;
uint16_t safety_counter;
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
delay(100);
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
// attempt to connect to Wifi network:
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
// wait 1 second for re-trying
delay(1000);
}
Serial.print("\n");
Serial.print(F("Connected to: "));
Serial.println(ssid);
// Etablishing Connection
Serial.println(F("Establishing Connection... "));
if (sh2lib_connect(&hd, "My_Server") != ESP_OK)
{
Serial.println("Error connecting to HTTP2 server");
//vTaskDelete(NULL);
}
Serial.println(F("Connected to the webserver"));
delay(1000);
// Configuring the Cam
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
// init with high specs to pre-allocate larger buffers
if(psramFound())
{
config.frame_size = FRAMESIZE_VGA;// FRAMESIZE_QVGA
config.jpeg_quality = 10; //0-63 lower number means higher quality
config.fb_count = 2;
}
else
{
config.frame_size = FRAMESIZE_CIF;
config.jpeg_quality = 12; //0-63 lower number means higher quality
config.fb_count = 1;
}
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK)
{
Serial.printf("Camera init failed with error 0x%x", err);
delay(1000);
ESP.restart();
}
// This task handles the POST requests
xTaskCreatePinnedToCore(
task_http2
, "http2_task"
, (1024 * 24) // Stack size
, NULL
, 3 // Priority
, NULL
, ARDUINO_RUNNING_CORE);
Serial.println(F("Task Called"));
}
void loop()
{
// To prohibit the interference between resources, I used main loop to capture the Images
// Check if the posting has been finished
if (is_posted)
{
Serial.println(F("Call to Capture"));
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if(!fb)
{
Serial.println("Camera capture failed");
delay(1000);
ESP.restart();
}
// to check if the size is not bigger than 16K
uint32_t imageLen = fb->len;
if(imageLen<16000)
{
// Creating the body of the post
uint32_t extraLen = tail.length()+head.length();
totalLen = extraLen + imageLen;
uint8_t *fbBuf = fb->buf;
const char* head_char = head.c_str();
const char* tail_char = tail.c_str();
uint32_t totalLen_copy = totalLen;
char alpha[totalLen];
std::copy(head_char,head_char+head.length(), data_to_post);
std::copy(fbBuf,fbBuf+imageLen , data_to_post+head.length());
std::copy(tail_char,tail_char+ tail.length(), data_to_post+head.length()+imageLen);
esp_camera_fb_return(fb);
Serial.println(F("Camera captured"));
delay(100);
safety_counter++;
// Stopping capturing until posting is finished
is_captured = true;
is_posted = false;
}
}
delay(100);
}
int handle_get_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)
{
if (len > 0)
{
Serial.printf("%.*s\n", len, data);
}
if (flags == DATA_RECV_RST_STREAM)
{
Serial.println("STREAM CLOSED");
}
return 0;
}
int handle_post_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)
{
if (len > 0) {
Serial.printf("%.*s\n", len, data);
// decreasing the counter to prevent fault loop
safety_counter--;
}
//Serial.print(F("Safety_Counter in Response: ")); Serial.println(safety_counter);
if (flags == DATA_RECV_RST_STREAM) {
request_finished = true;
Serial.println("STREAM CLOSED");
}
return 0;
}
int send_post_data(struct sh2lib_handle *handle, char *buf, size_t length, uint32_t *data_flags)
{
// To check the body of the post
/*
Serial.println("Post Buffer");
for(int i;i<totalLen;i++)
Serial.print(data_to_post[i]);
Serial.println("Post Buffer End");
*/
if (totalLen < length)
{
memcpy(buf, data_to_post, totalLen);
}
else
{
Serial.println("Cannot write to buffer");
//copylen = 0;
}
(*data_flags) |= NGHTTP2_DATA_FLAG_EOF;
return totalLen;
}
void task_http2(void *args)
{
Serial.println(F("Task Runs"));
// Start capturing
is_posted = true;
int counter = 0;
for(;;)
{
// if capturing finished:
if(is_captured)
{
// after each five unsuccessful posts, reestablish the connection
Serial.print(F("Safety_Counter is: ")); Serial.println(safety_counter);
if(safety_counter>5)
{
is_posted = false;
vTaskDelay(100);
counter = 0;
safety_counter = 0;
sh2lib_free(&hd);
vTaskDelay(100);
Serial.println(F("Safety Counter Occured ... "));
if (sh2lib_connect(&hd, "My_Server") != ESP_OK)
{
Serial.println("Error connecting to HTTP2 server");
//vTaskDelete(NULL);
}
Serial.println(F("Connected to the webserver"));
vTaskDelay(1000);
// Preparing capturing again
is_posted = true;
is_captured = false;
continue;
}
char len[20];
sprintf(len, "%d",totalLen); //length_of_body);
Serial.print("the length is: ");
Serial.println(len);
const nghttp2_nv nva[] = { SH2LIB_MAKE_NV(":method", "POST"),
SH2LIB_MAKE_NV(":scheme", "https"),
SH2LIB_MAKE_NV(":authority", hd.hostname),
SH2LIB_MAKE_NV(":path", "/mvp/upload_image"),
SH2LIB_MAKE_NV("Content-Length", len),
SH2LIB_MAKE_NV("Content-Type", "multipart/form-data; boundary=JPEG_IMAGE")
};
sh2lib_do_putpost_with_nv(&hd, nva, sizeof(nva) / sizeof(nva[0]), send_post_data, handle_post_response);
while (1)
{
if (sh2lib_execute(&hd) != ESP_OK)
{
Serial.println("Error in execute");
break;
}
if (request_finished)
{
// a general counter to reestablish the connection
counter++;
break;
}
//vTaskDelay(1000);
}
}
// General counter
if(counter>30)
{
counter = 0;
sh2lib_free(&hd);
vTaskDelay(100);
Serial.println(F("Establishing Connection... "));
if (sh2lib_connect(&hd, "My_Server") != ESP_OK)
{
Serial.println("Error connecting to HTTP2 server");
//vTaskDelete(NULL);
}
Serial.println(F("Connected to the webserver"));
}
is_captured = false;
is_posted = true;
Serial.println("Sending finished");
vTaskDelay(1000);
}
}

Send data from NodeMcu(ESP266) to ESP32 using esp now?

I am trying to send some data from a Nodemcu(esp8266) to ESP32. I am trying to use espnow for that purpose, but I am really stuck, I cant merge the Master and Slave for both the boards, I find the codes to be far different I tried some modifications and I can send data from the Nodemcu but can't receive it on the ESP32. I am trying to send two analog values for a Gesture control car.
The master code or the controller code running on the Nodemcu is given below
#include <ESP8266WiFi.h>
#include <espnow.h>
#define MUX_A D4
#define MUX_B D3
#define MUX_C D2
#define ANALOG_INPUT A0
#define CHANNEL 4
extern "C" {
}
uint8_t remoteMac[] = {0x24, 0x6F, 0x28, 0xB6, 0x24, 0x49};
struct __attribute__((packed)) DataStruct {
//char text[32];
int x;
int y;
unsigned long time;
};
DataStruct myData;
unsigned long lastSentMillis;
unsigned long sendIntervalMillis = 1000;
unsigned long sentMicros;
unsigned long ackMicros;
int xAxis;
int yAxis;
int zAxis;
void InitESPNow() {
WiFi.disconnect();
if (esp_now_init()==0) {
Serial.println("ESPNow Init Success");
}
else {
Serial.println("ESPNow Init Failed");
// Retry InitESPNow, add a counte and then restart?
// InitESPNow();
// or Simply Restart
ESP.restart();
}
}
void sendData() {
if (millis() - lastSentMillis >= sendIntervalMillis) {
lastSentMillis += sendIntervalMillis;
myData.time = millis();
uint8_t bs[sizeof(myData)];
memcpy(bs, &myData, sizeof(myData));
sentMicros = micros();
esp_now_send(NULL, bs, sizeof(myData)); // NULL means send to all peers
Serial.println("sent data");
Serial.println(myData.x);
Serial.println(myData.y);
}
}
void sendCallBackFunction(uint8_t* mac, uint8_t sendStatus) {
ackMicros = micros();
Serial.print("Trip micros "); Serial.println(ackMicros - sentMicros);
Serial.printf("Send status = %i", sendStatus);
Serial.println();
Serial.println();
}
void setup() {
Serial.begin(115200); Serial.println();
Serial.println("Starting EspnowController.ino");
WiFi.mode(WIFI_STA); // Station mode for esp-now controller
WiFi.disconnect();
Serial.printf("This mac: %s, ", WiFi.macAddress().c_str());
Serial.printf("slave mac: %02x%02x%02x%02x%02x%02x", remoteMac[0], remoteMac[1], remoteMac[2], remoteMac[3], remoteMac[4], remoteMac[5]);
Serial.printf(", channel: %i\n",CHANNEL);
InitESPNow();
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
esp_now_add_peer(remoteMac, ESP_NOW_ROLE_SLAVE, CHANNEL, NULL, 0);
esp_now_register_send_cb(sendCallBackFunction);
Serial.print("Message ");
pinMode(MUX_A, OUTPUT);
pinMode(MUX_B, OUTPUT);
pinMode(MUX_C, OUTPUT);
Serial.println("Setup finished");
}
void changeMux(int c, int b, int a) {
digitalWrite(MUX_A, a);
digitalWrite(MUX_B, b);
digitalWrite(MUX_C, c);
}
void loop() {
changeMux(LOW, LOW, LOW);
xAxis = analogRead(ANALOG_INPUT); //Value of the sensor connected to pin 0 of IC
changeMux(LOW, LOW, HIGH);
yAxis = analogRead(ANALOG_INPUT); //Value of the sensor connected to pin 1 of IC
changeMux(LOW, HIGH, LOW);
zAxis = analogRead(ANALOG_INPUT); //Value of the sensor connected to pin 2 of IC
changeMux(LOW, HIGH, LOW);
myData.x= xAxis;
myData.y= yAxis;
sendData();
delay(500);
}
The slave code running on the ESP32 is given below
#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>
#define CHANNEL 4
uint8_t mac[] = {0x36, 0x33, 0x33, 0x33, 0x33, 0x33};
struct __attribute__((packed)) DataStruct {
//char text[32];
int x;
int y;
unsigned long time;
};
DataStruct myData;
// Init ESP Now with fallback
void setup() {
Serial.begin(115200);
Serial.println("ESPNow/Basic/Slave Example");
//Set device in AP mode to begin with
WiFi.mode(WIFI_AP);
// configure device AP mode
// This is the mac address of the Slave in AP Mode
esp_wifi_set_mac(ESP_IF_WIFI_STA, &mac[0]);
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
// Init ESPNow with a fallback logic
if (esp_now_init()!=0) {
Serial.println("*** ESP_Now init failed");
while(true) {};
}
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info.
esp_now_register_recv_cb(OnDataRecv);
Serial.print("Aheloiioi");
}
// callback when data is recv from Master
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
memcpy(&myData, data, sizeof(myData));
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.print("Last Packet Recv from: "); Serial.println(macStr);
Serial.print("Last Packet Recv Data: "); Serial.println(myData.x); Serial.println(myData.y);
Serial.println("");
}
void loop() {
// Chill
}
This is the only output I get on the ESP32
ESPNow/Basic/Slave Example
AP MAC: 24:6F:28:B6:24:49
Aheloiioi
While this is the output on Nodemcu
Starting EspnowController.ino
This mac: BC:DD:C2:B5:E3:2B, slave mac: 246f28b62449, channel: 4
ESPNow Init Success
Message Setup finished
sent data
10
8
Trip micros 7320
Send status = 1
sent data
9
8
Trip micros 6817
Send status = 1
sent data
10
9
Trip micros 6731
Send status = 1
and it continues
If there are any other methods to send data, please do mention
I never use esp_now before so I didn't test it myself, but I think this has nothing to do with the library or esp32, it is just a minor mistake of c++ usage.
On your sendData() function of your esp8266, you did this:
uint8_t bs[sizeof(myData)];
memcpy(bs, &myData, sizeof(myData));
sentMicros = micros();
esp_now_send(NULL, bs, sizeof(myData));
The bs has a type of uint8_t and is an array, and you try to copy the data that has a type of struct myData into the array. And you then try to pass the array into the esp_now_send(). I quickly took a look at the esp_now_send() function prototype definition, the esp_now_send() need to pass in the address (which has a type of uint8_t) of your data structure myData.
I don't know know why you need to do the memcpy, but I think it will easier and simply to just directly pass in the pointer of myData into the function call.
void sendData() {
if (millis() - lastSentMillis >= sendIntervalMillis) {
lastSentMillis += sendIntervalMillis;
myData.time = millis();
esp_now_send(NULL, (uint8_t *)&myData, sizeof(myData)); // NULL means send to all peers
Serial.println("sent data");
Serial.println(myData.x);
Serial.println(myData.y);
}
}
Please let me know if this work?

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

Socket with IOS cocos2dx

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.

A question of libevent example code: how is invoked?

I'm learning libev however the code is so hard to understand, so I choose to learn libevent first whose code is relatively clearer. But I encounter a problem when try the example (http://www.wangafu.net/~nickm/libevent-book/01_intro.html).
How is the code event_add(state->write_event, NULL) in do_read() make do_write() function invoked?
/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For fcntl */
#include <fcntl.h>
#include <event2/event.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#define MAX_LINE 16384
void do_read(evutil_socket_t fd, short events, void *arg);
void do_write(evutil_socket_t fd, short events, void *arg);
char
rot13_char(char c)
{
return c;
/* We don't want to use isalpha here; setting the locale would change
* which characters are considered alphabetical. */
if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
return c + 13;
else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
return c - 13;
else
return c;
}
struct fd_state {
char buffer[MAX_LINE];
size_t buffer_used;
size_t n_written;
size_t write_upto;
struct event *read_event;
struct event *write_event;
};
struct fd_state *
alloc_fd_state(struct event_base *base, evutil_socket_t fd)
{
struct fd_state *state = malloc(sizeof(struct fd_state));
if (!state)
return NULL;
state->read_event = event_new(base, fd, EV_READ|EV_PERSIST, do_read, state);
if (!state->read_event) {
free(state);
return NULL;
}
state->write_event =
event_new(base, fd, EV_WRITE|EV_PERSIST, do_write, state);
if (!state->write_event) {
event_free(state->read_event);
free(state);
return NULL;
}
state->buffer_used = state->n_written = state->write_upto = 0;
assert(state->write_event);
return state;
}
void
free_fd_state(struct fd_state *state)
{
event_free(state->read_event);
event_free(state->write_event);
free(state);
}
void
do_read(evutil_socket_t fd, short events, void *arg)
{
struct fd_state *state = arg;
char buf[1024];
int i;
ssize_t result;
while (1) {
assert(state->write_event);
result = recv(fd, buf, sizeof(buf), 0);
if (result <= 0)
break;
for (i=0; i < result; ++i) {
if (state->buffer_used < sizeof(state->buffer))
state->buffer[state->buffer_used++] = rot13_char(buf[i]);
if (buf[i] == '\n') {
assert(state->write_event);
**event_add(state->write_event, NULL);**
state->write_upto = state->buffer_used;
}
}
}
if (result == 0) {
free_fd_state(state);
} else if (result < 0) {
if (errno == EAGAIN) // XXXX use evutil macro
return;
perror("recv");
free_fd_state(state);
}
}
void
**do_write(evutil_socket_t fd, short events, void *arg)**
{
struct fd_state *state = arg;
while (state->n_written < state->write_upto) {
ssize_t result = send(fd, state->buffer + state->n_written,
state->write_upto - state->n_written, 0);
if (result < 0) {
if (errno == EAGAIN) // XXX use evutil macro
return;
free_fd_state(state);
return;
}
assert(result != 0);
state->n_written += result;
}
if (state->n_written == state->buffer_used)
state->n_written = state->write_upto = state->buffer_used = 1;
event_del(state->write_event);
}
void
do_accept(evutil_socket_t listener, short event, void *arg)
{
struct event_base *base = arg;
struct sockaddr_storage ss;
socklen_t slen = sizeof(ss);
int fd = accept(listener, (struct sockaddr*)&ss, &slen);
if (fd < 0) { // XXXX eagain??
perror("accept");
} else if (fd > FD_SETSIZE) {
close(fd); // XXX replace all closes with EVUTIL_CLOSESOCKET */
} else {
struct fd_state *state;
evutil_make_socket_nonblocking(fd);
state = alloc_fd_state(base, fd);
assert(state); /*XXX err*/
assert(state->write_event);
event_add(state->read_event, NULL);
}
}
void
run(void)
{
evutil_socket_t listener;
struct sockaddr_in sin;
struct event_base *base;
struct event *listener_event;
base = event_base_new();
if (!base)
return; /*XXXerr*/
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(40713);
listener = socket(AF_INET, SOCK_STREAM, 0);
evutil_make_socket_nonblocking(listener);
#ifndef WIN32
{
int one = 1;
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
}
#endif
if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
perror("bind");
return;
}
if (listen(listener, 16)<0) {
perror("listen");
return;
}
listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);
/*XXX check it */
event_add(listener_event, NULL);
event_base_dispatch(base);
}
int
main(int c, char **v)
{
setvbuf(stdout, NULL, _IONBF, 0);
run();
return 0;
}
I'm not sure if I'm answering the same question you asked - I understand it as:
How does calling event_add(state->write_event, NULL) in do_read() lead to do_write() being invoked?
The key to figuring this out is understanding what the do_read() function is actually doing. do_read() is a callback function associated with a socket which has data to be read: this is set up with allocate_fd_state():
struct fd_state *
alloc_fd_state(struct event_base *base, evutil_socket_t fd)
{
/*
* Allocate a new fd_state structure, which will hold our read and write events
* /
struct fd_state *state = malloc(sizeof(struct fd_state));
[...]
/*
* Initialize a read event on the given file descriptor: associate the event with
* the given base, and set up the do_read callback to be invoked whenever
* data is available to be read on the file descriptor.
* /
state->read_event = event_new(base, fd, EV_READ|EV_PERSIST, do_read, state);
[...]
/*
* Set up another event on the same file descriptor and base, which invoked the
* do_write callback anytime the file descriptor is ready to be written to.
*/
state->write_event =
event_new(base, fd, EV_WRITE|EV_PERSIST, do_write, state);
[...]
return state;
}
At this point, though, neither of these events have been event_add()'ed to the event_base base. The instructions for what to do are all written out, but no one is looking at them. So how does anything get read? state->read_event is event_add()'ed to the base after an incoming connection is made. Look at do_accept():
void
do_accept(evutil_socket_t listener, short event, void *arg)
{
[ ... accept a new connection and give it a file descriptor fd ... ]
/*
* If the file descriptor is invalid, close it.
*/
if (fd < 0) { // XXXX eagain??
perror("accept");
} else if (fd > FD_SETSIZE) {
close(fd); // XXX replace all closes with EVUTIL_CLOSESOCKET */
/*
* Otherwise, if the connection was successfully accepted...
*/
} else {
[ ... allocate a new fd_state structure, and make the file descriptor non-blocking ...]
/*
* Here's where the magic happens. The read_event created back in alloc_fd_state()
* is finally added to the base associated with it.
*/
event_add(state->read_event, NULL);
}
}
So right after accepting a new connection, the program tells libevent to wait until there's data available on the connection, and then run the do_read() callback. At this point, it's still impossible for do_write() to be called. It needs to be event_add()'ed. This happens in do_read():
void
do_read(evutil_socket_t fd, short events, void *arg)
{
/* Create a temporary buffer to receive some data */
char buf[1024];
while (1) {
[ ... Receive the data, copying it into buf ... ]
[ ... if there is no more data to receive, or there was an error, exit this loop... ]
[ ... else, result = number of bytes received ... ]
for (i=0; i < result; ++i) {
[ ... if there's room in the buffer, copy in the rot13() encoded
version of the received data ... ]
/*
* Boom, headshot. If we've reached the end of the incoming data
* (assumed to be a newline), then ...
*/
if (buf[i] == '\n') {
[...]
/*
* Have libevent start monitoring the write_event, which calls do_write
* as soon as the file descriptor is ready to be written to.
*/
event_add(state->write_event, NULL);
[...]
}
}
}
[...]
}
So, after reading in some data from a file descriptor, the program starts waiting until
the file descriptor is ready to be written to, and then invokes do_write(). Program
flow looks like this:
[ set up an event_base and start waiting for events ]
[ if someone tries to connect ]
[ accept the connection ]
[ ... wait until there is data to read on the connection ... ]
[ read in data from the connection until there is no more left ]
[ ....wait until the connection is ready to be written to ... ]
[ write out our rot13() encoded response ]
I hope that a) that was the correct interpretation of your question, and b) this was a helpful answer.

Resources