I want to make both the existing singal handler in the project and my own singal handler co-exist so that both can properly capture singal.
typedef void (*signalHandler)(int signo, siginfo_t *info, void *context);
static signalHandler previousSignalHandler = NULL;
void signalExceptionHandler(int signal, siginfo_t* info, void* context)
{
NSMutableString *mstr = [[NSMutableString alloc] init];
[mstr appendString:#"Stack:\n"];
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i <frames; ++i) {
[mstr appendFormat:#"%s\n", strs[i]];
}
BYLOGI(#"%#",mstr);
[BYCrashCacheHelper saveAppCrashDataWithCrashInfo:mstr];
if (previousSignalHandler) {
previousSignalHandler(signal, info, context);
}
}
void signalRegister(int signal)
{
struct sigaction action;
action.sa_sigaction = signalExceptionHandler;
action.sa_flags = SA_NODEFER | SA_SIGINFO;
sigemptyset(&action.sa_mask);
sigaction(signal, &action, 0);
}
void judgePreviousSignalHandlerAndSignalRegister(int signal)
{
struct sigaction old_action;
sigaction(signal, NULL, &old_action);
if (old_action.sa_flags & SA_SIGINFO) {
previousSignalHandler = old_action.sa_sigaction;
}
signalRegister(signal);
}
void installSignalHandler(void)
{
judgePreviousSignalHandlerAndSignalRegister(SIGHUP);
judgePreviousSignalHandlerAndSignalRegister(SIGINT);
judgePreviousSignalHandlerAndSignalRegister(SIGQUIT);
judgePreviousSignalHandlerAndSignalRegister(SIGABRT);
judgePreviousSignalHandlerAndSignalRegister(SIGILL);
judgePreviousSignalHandlerAndSignalRegister(SIGSEGV);
judgePreviousSignalHandlerAndSignalRegister(SIGFPE);
judgePreviousSignalHandlerAndSignalRegister(SIGBUS);
judgePreviousSignalHandlerAndSignalRegister(SIGPIPE);
}
I found the above method in some blogs, but after debugging, I found that it can not get to the previous handler.
Excuse me, how to get the previous handler correctly, and avoid the handler coverage problem?
Related
Here is the scenario. I have an esp32, 2 led's and a ios example app I found online here. Currently If I press a button on my esp32 it notifies the ios app to display "1", if pressed again it displays "0". This works perfectly.
The tricky part is that this ios app allows me to send a write command to the esp32. I'd like to make it so if '1' is sent LED A turns ON and LED B turns OFF, then LED A OFF and LED B ON when 0 is sent. I am unable to do this though. Try as I might I can't figure out where in the chain of this project something is wrong. Maybe the code on the esp32 or maybe the app i'm unsure.
Here is my arduino code. (There is more to the code not mentioned, I actually have 4 led's but I only want to turn on 2 certain ones when a write command is sent).
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
boolean oldState = LOW;
uint32_t value = 0;
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}
Serial.println();
if (rxValue.find("1") != -1) {
digitalWrite(13, HIGH);
digitalWrite(27, LOW);
}
else if (rxValue.find("0") != -1) {
digitalWrite(13, LOW);
digitalWrite(27, HIGH);
}
}
}
};
const int bt1 = 14;
boolean bt1g = true;
int bt1t = 0;
void setup() {
pinMode(13, OUTPUT);
pinMode(15, OUTPUT);
pinMode(33, OUTPUT);
pinMode(27, OUTPUT);
pinMode(bt1, INPUT_PULLUP);
Serial.begin(9600);
BLEDevice::init("ESP32");
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0);
BLEDevice::startAdvertising();
Serial.println("Waiting a client connection to notify...");
}
void loop()
{
if (bt1g) {
if (digitalRead(bt1) == LOW ) {
bt1t = (bt1t + 1) % 2;
Serial.println(bt1t);
bt1g = false;
}
}
if (!bt1g) {
if (digitalRead(bt1) == HIGH) {
bt1g = true;
}
}
if (bt1t == 0) {
digitalWrite(15, LOW);
digitalWrite(33, HIGH);
}
}
boolean newState = digitalRead(15);
if (deviceConnected) {
if (newState != oldState) {
if (newState == LOW) {
pCharacteristic->setValue("1");
}
else {
pCharacteristic->setValue("0");
}
pCharacteristic->notify();
};
oldState = newState;
}
delay(50);
}
It looks like the entire code for the ios app is too long to submit to this post so here is the github
I'm really unsure and stuck in a rut. Any help is appreciated!
Could it be you are not discovering the correct characteristics? It looks like you only have one service and one characteristic.
I am trying to develop a native web view app and it is working good.
But every time I close and restart the app all login/cookie information is lost.
How can I store and restore cookies in a native web view?
What is very weird: The HTML5 Web Storage (local db) gets restored, but the cookies aren't available anymore!?
Do you have any information for me?
Here is the basic code that I am using (from a Samsung example):
#include "webviewexample.h"
// Header files needed for EWK Webkit
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Ecore_Getopt.h>
#include <Eet.h>
#include <Eina.h>
#include <Elementary.h>
#include <Evas.h>
#include <EWebKit.h>
#include <app.h>
typedef struct appdata {
Evas_Object *win;
Evas_Object *conform;
Evas_Object *label;
Evas_Object *entry;
Evas_Object *web_view;
Evas_Object *back_button;
Evas_Object *forward_button;
} appdata_s;
static void
win_back_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s *ad = data;
/* Let window go to hide state. */
elm_win_iconified_set(ad->win, EINA_TRUE);
}
static void
btn_go_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s* ad = data;
ewk_view_url_set(ad->web_view, elm_object_text_get(ad->entry) );
}
static void
btn_prev_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s* ad = data;
if( ewk_view_back_possible( ad->web_view ) == EINA_TRUE )
ewk_view_back( ad->web_view );
}
static void
btn_next_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s* ad = data;
if( ewk_view_forward_possible( ad->web_view ) == EINA_TRUE )
ewk_view_forward( ad->web_view );
}
static void
my_table_pack(Evas_Object *table, Evas_Object *child, int x, int y, int w, int h)
{
evas_object_size_hint_align_set(child, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_weight_set(child, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_table_pack(table, child, x, y, w, h);
evas_object_show(child);
}
static void
create_base_gui(appdata_s *ad)
{
/* set up policy to exit when last window is closed */
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
/* Window */
ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
elm_win_autodel_set(ad->win, EINA_TRUE);
int rots[4] = { 0, 90, 180, 270 };
elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4);
eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, win_back_cb, ad);
{
/* Box to put the table in so we can bottom-align the table
* window will stretch all resize object content to win size */
Evas_Object *box = elm_box_add(ad->win);
evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(ad->win, box);
evas_object_show(box);
/* Table */
Evas_Object *table = elm_table_add(ad->win);
/* Make table homogenous - every cell will be the same size */
elm_table_homogeneous_set(table, EINA_TRUE);
/* Set padding of 10 pixels multiplied by scale factor of UI */
elm_table_padding_set(table, 5 * elm_config_scale_get(), 10 * elm_config_scale_get());
/* Let the table child allocation area expand within in the box */
evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
/* Set table to fiill width but align to bottom of box */
evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(box, table);
evas_object_show(table);
{
/* Entry */
ad->entry = elm_entry_add(ad->win);
elm_entry_scrollable_set(ad->entry, EINA_TRUE);
eext_entry_selection_back_event_allow_set(ad->entry, EINA_TRUE);
elm_object_text_set(ad->entry, "http://www.tizen.org");
my_table_pack(table, ad->entry, 0, 0, 3, 1);
/* Button-1 */
Evas_Object *btn = elm_button_add(ad->win);
elm_object_text_set(btn, "Prev");
evas_object_smart_callback_add(btn, "clicked", btn_prev_cb, ad);
my_table_pack(table, btn, 0, 1, 1, 1);
/* Button-2 */
btn = elm_button_add(ad->win);
elm_object_text_set(btn, "Go");
evas_object_smart_callback_add(btn, "clicked", btn_go_cb, ad);
my_table_pack(table, btn, 1, 1, 1, 1);
/* Button-3 */
btn = elm_button_add(ad->win);
elm_object_text_set(btn, "Next");
evas_object_smart_callback_add(btn, "clicked", btn_next_cb, ad);
my_table_pack(table, btn, 2, 1, 1, 1);
/* WebView */
Evas *evas = evas_object_evas_get(ad->win);
ad->web_view = ewk_view_add(evas);
ewk_view_url_set(ad->web_view, elm_object_text_get(ad->entry) );
my_table_pack(table, ad->web_view, 0, 2, 3, 8);
}
}
/* Show window after base gui is set up */
evas_object_show(ad->win);
}
static bool
app_create(void *data)
{
/* Hook to take necessary actions before main event loop starts
Initialize UI resources and application's data
If this function returns true, the main loop of application starts
If this function returns false, the application is terminated */
appdata_s *ad = data;
create_base_gui(ad);
return true;
}
static void
app_control(app_control_h app_control, void *data)
{
/* Handle the launch request. */
}
static void
app_pause(void *data)
{
/* Take necessary actions when application becomes invisible. */
}
static void
app_resume(void *data)
{
/* Take necessary actions when application becomes visible. */
}
static void
app_terminate(void *data)
{
/* Release all resources. */
ewk_shutdown();
}
static void
ui_app_lang_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LANGUAGE_CHANGED*/
char *locale = NULL;
system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale);
elm_language_set(locale);
free(locale);
return;
}
int
main(int argc, char *argv[])
{
appdata_s ad = {0,};
memset(&ad, 0x00, sizeof(appdata_s));
int ret = 0;
ui_app_lifecycle_callback_s event_callback = {0,};
memset(&event_callback, 0x00, sizeof(ui_app_lifecycle_callback_s));
app_event_handler_h handlers[5] = {NULL, };
event_callback.create = app_create;
event_callback.terminate = app_terminate;
event_callback.pause = app_pause;
event_callback.resume = app_resume;
event_callback.app_control = app_control;
ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, ui_app_lang_changed, &ad);
ret = ui_app_main(argc, argv, &event_callback, &ad);
if (ret != APP_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "app_main() is failed. err = %d", ret);
}
return ret;
}
The manifest file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<manifest xmlns="http://tizen.org/ns/packages" api-version="2.4" package="org.example.webviewexample" version="1.0.0">
<profile name="mobile"/>
<ui-application appid="org.example.webviewexample" exec="webviewexample" launch_mode="single" multiple="false" nodisplay="false" taskmanage="true" type="capp">
<label>webviewexample</label>
<icon>webviewexample.png</icon>
</ui-application>
<privileges>
<privilege>http://tizen.org/privilege/network.get</privilege>
<privilege>http://tizen.org/privilege/appmanager.launch</privilege>
<privilege>http://tizen.org/privilege/location</privilege>
<privilege>http://tizen.org/privilege/internet</privilege>
<privilege>http://tizen.org/privilege/notification</privilege>
<privilege>http://tizen.org/privilege/display</privilege>
<privilege>http://tizen.org/privilege/camera</privilege>
<privilege>http://tizen.org/privilege/externalstorage</privilege>
<privilege>http://tizen.org/privilege/content.write</privilege>
</privileges>
</manifest>
You may Checkout the EWebKit: WebView API References for API functions related to Cookies.
relevant terms/functions on API references:
Ewk Cookie Manager,
Ewk_Cookie_Persistent_Storage,
ewk_cookie_manager_persistent_storage_set (),
Ewk_Cookie_Accept_Policy
Thank you for the answer, but I have not been able to solve it.
I have now solved it via a workaround:
1. via Javascript I save the cookies in the LocalStorage.
2. when starting the app I read the data from the LocalStorage and create the cookies again.
That's how it works for me.
I would like to know how to create a timer in macOS / iOS. In linux you can create it using timer_create() function of time.h class but in macOS / iOS this function don't exist.
Something like NSTimer (objective-c) but in C.
Thanks
After updating the link for Grand Central Dispatch timers (Apple's page) on a previous answer, I created some example code for two timers. It should be noted that this works on FreeBSD and MacOS, but not Linux (without GCD support). The example creates two event timers, one that fires 0.2sec and one that fires 0.5sec over a total of 20 times. There is a 1 second delay that exists before execution starts. The sleep() functions are not used.
#include <dispatch/dispatch.h>
#include <stdio.h>
#include <stdlib.h>
int i = 0;
dispatch_queue_t queue;
dispatch_source_t timer1;
dispatch_source_t timer2;
void sigtrap(int sig)
{
dispatch_source_cancel(timer1);
dispatch_source_cancel(timer2);
printf("CTRL-C received, exiting program\n");
exit(EXIT_SUCCESS);
}
void vector1(dispatch_source_t timer)
{
printf("a: %d\n", i);
i++;
if (i >= 20)
{
dispatch_source_cancel(timer);
}
}
void vector2(dispatch_source_t timer)
{
printf("b: %d\n", i);
i++;
if (i >= 20) //at 20 count cancel the
{
dispatch_source_cancel(timer);
}
}
int main(int argc, const char* argv[]) {
signal(SIGINT, &sigtrap); //catch the cntl-c
queue = dispatch_queue_create("timerQueue", 0);
// Create dispatch timer source
timer1 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
timer2 = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// Set block for dispatch source when catched events
dispatch_source_set_event_handler(timer1, ^{vector1(timer1);});
dispatch_source_set_event_handler(timer2, ^{vector2(timer2);});
// Set block for dispatch source when cancel source
dispatch_source_set_cancel_handler(timer1, ^{
dispatch_release(timer1);
dispatch_release(queue);
printf("end\n");
exit(0);
});
dispatch_source_set_cancel_handler(timer2, ^{
dispatch_release(timer2);
dispatch_release(queue);
printf("end\n");
exit(0);
});
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC); // after 1 sec
// Set timer
dispatch_source_set_timer(timer1, start, NSEC_PER_SEC / 5, 0); // 0.2 sec
dispatch_source_set_timer(timer2, start, NSEC_PER_SEC / 2, 0); // 0.5 sec
printf("start\n");
dispatch_resume(timer1);
dispatch_resume(timer2);
while(1)
{
;;
}
return 0;
}
You can use pthreads for macOS, with some combination of sleep and time
typedef struct Timer {
void (*fn)(void);
bool (*timer_delegate)(pthread_t, unsigned int, unsigned int);
unsigned int seconds;
} Timer;
void* timer_run(void *t) {
unsigned int start_time = time(NULL);
while(1) {
Timer tmr = *((Timer *) t);
bool should_kill_thread = tmr.timer_delegate(pthread_self(), start_time, time(NULL));
if (should_kill_thread) pthread_cancel(pthread_self());
tmr.fn();
sleep(tmr.seconds);
}
}
bool should_kill_thread(pthread_t t, unsigned int start_time, unsigned int utime_new) {
printf("the start time was %d and the new time is %d \n", start_time, utime_new);
if (utime_new - start_time >= 9) {
return true;
}
return false;
}
void hello_world() {
printf("%s\n", "Hello, World!");
}
int main(int argc, char const *argv[])
{
pthread_t t1;
Timer args;
args.fn = &hello_world;
args.timer_delegate = should_kill_thread;
args.seconds = 1; // call every 1 second
int id = pthread_create(&t1, NULL, timer_run, &args);
if (id) {
printf("ERROR; return code from pthread_create() is %d\n", id);
exit(EXIT_FAILURE);
}
pthread_join(t1, NULL); // blocks main thread
printf("%s\n", "DONE"); // never reached until t1 is killed
return 0;
}
Expanding on b_degnan's answer above (click that one), we had to (partially) support Linux code using timers, so we wrote a time.h that we could use directly.
#include <sys/stdtypes.h>
#include <stdbool.h>
#include <mach/boolean.h>
#include <sys/errno.h>
#include <stdlib.h>
#include <dispatch/dispatch.h>
#if !defined(MAC_OS_X_VERSION_10_12) || \
(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12)
typedef int clockid_t;
#endif
struct itimerspec {
struct timespec it_interval; /* timer period */
struct timespec it_value; /* timer expiration */
};
struct sigevent;
/* If used a lot, queue should probably be outside of this struct */
struct macos_timer {
dispatch_queue_t tim_queue;
dispatch_source_t tim_timer;
void (*tim_func)(union sigval);
void *tim_arg;
};
typedef struct macos_timer *timer_t;
static inline void
_timer_cancel(void *arg)
{
struct macos_timer *tim = (struct macos_timer *)arg;
dispatch_release(tim->tim_timer);
dispatch_release(tim->tim_queue);
tim->tim_timer = NULL;
tim->tim_queue = NULL;
free(tim);
}
static inline void
_timer_handler(void *arg)
{
struct macos_timer *tim = (struct macos_timer *)arg;
union sigval sv;
sv.sival_ptr = tim->tim_arg;
if (tim->tim_func != NULL)
tim->tim_func(sv);
}
static inline int
timer_create(clockid_t clockid, struct sigevent *sevp,
timer_t *timerid)
{
struct macos_timer *tim;
*timerid = NULL;
switch (clockid) {
case CLOCK_REALTIME:
/* What is implemented so far */
if (sevp->sigev_notify != SIGEV_THREAD) {
errno = ENOTSUP;
return (-1);
}
tim = (struct macos_timer *)
malloc(sizeof (struct macos_timer));
if (tim == NULL) {
errno = ENOMEM;
return (-1);
}
tim->tim_queue =
dispatch_queue_create("timerqueue",
0);
tim->tim_timer =
dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
0, 0, tim->tim_queue);
tim->tim_func = sevp->sigev_notify_function;
tim->tim_arg = sevp->sigev_value.sival_ptr;
*timerid = tim;
/* Opting to use pure C instead of Block versions */
dispatch_set_context(tim->tim_timer, tim);
dispatch_source_set_event_handler_f(tim->tim_timer,
_timer_handler);
dispatch_source_set_cancel_handler_f(tim->tim_timer,
_timer_cancel);
return (0);
default:
break;
}
errno = EINVAL;
return (-1);
}
static inline int
timer_settime(timer_t tim, int flags,
const struct itimerspec *its, struct itimerspec *remainvalue)
{
if (tim != NULL) {
/* Both zero, is disarm */
if (its->it_value.tv_sec == 0 &&
its->it_value.tv_nsec == 0) {
/* There's a comment about suspend count in Apple docs */
dispatch_suspend(tim->tim_timer);
return (0);
}
dispatch_time_t start;
start = dispatch_time(DISPATCH_TIME_NOW,
NSEC_PER_SEC * its->it_value.tv_sec +
its->it_value.tv_nsec);
dispatch_source_set_timer(tim->tim_timer, start,
NSEC_PER_SEC * its->it_value.tv_sec +
its->it_value.tv_nsec,
0);
dispatch_resume(tim->tim_timer);
}
return (0);
}
static inline int
timer_delete(timer_t tim)
{
/* Calls _timer_cancel() */
if (tim != NULL)
dispatch_source_cancel(tim->tim_timer);
return (0);
}
Or, as a gist:
https://gist.github.com/lundman/731d0d7d09eca072cd1224adb00d9b9e
I'd be happy to receive updates, if you enhance it further with more types. It can clearly be improved, but does just enough for our needs.
Went with straight C here, since it is a port of upstream source.
Here's how I initialize SDL:
//initialize engine and set main loop callback... kind of awkward is there a better way to do this?
extern "C"{
CBCore::Engine *engine;
void UpdateLoop(void *f)
{
engine->updateLoop();
}
int main(int argc, char *argv[])
{
engine = new CBCore::Engine();
engine->init();
Assert(engine->window(), "Window not set for iOS animation callback");
SDL_iPhoneSetAnimationCallback(engine->window(), 1, UpdateLoop, NULL);
return 0;
}
}
//init function of engine, initializes required SDL subsystems and creates window
void Engine::init()
{
SDL_Log("Initializing engine!");
/* initialize SDL */
if(SDL_Init(0) != 0){
Assert(0, "Could not initialize SDL");
}
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
Assert(0, "Could not initialize SDL Video");
}
if(SDL_InitSubSystem(SDL_INIT_TIMER) != 0){
Assert(0, "Could not initialize SDL Timer");
}
_window = SDL_CreateWindow(NULL, 0, 0, 480, 320, SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS | SDL_WINDOW_OPENGL);
Assert(_window, "Could not create window");
_context = SDL_GL_CreateContext(pimpl->window);
Assert(_context, "Could not create context");
SDL_Log("Engine successfully initialized!");
}
//loop
void Engine::updateLoop()
{
SDL_Event event;
SDL_Log("Polling events");
while(SDL_PollEvent(&event)) {
SDL_Log("Polled event %d", event.type);
}
}
The loop gets called and I get 4 Events at startup: SDL_APP_DIDENTERFOREGROUND, SDL_WINDOWEVENT_SIZE_CHANGED, SDL_WINDOWEVENT_SHOWN and SDL_WINDOWEVENT_ENTER; I also got enter background messages and the likes. But I can click/touch on the simulator/device till the cows go home but no event is received... Am I missing something?
I was finally able to solve it by calling SDL_GL_SwapWindow, after that events get processed.
I have been having a lot of trouble finding a way to query the DNS to find the NAPTR in iOS. There seem to be many relatively simple ways to resolve to an IP, but I specifically need to find all NAPTR records in a DNS lookup. I'd prefer to do so without having to bring in any external libraries if at all possible. If anyone has been able to do this (or something similar that I can extrapolate from) I'd appreciate any pointers.
All code must function in iOS 5.0+
I ended up using DNSServiceQueryRecord.
DNSServiceRef sdRef;
DNSServiceQueryRecord(&sdRef, 0, 0,
"google.com",
kDNSServiceType_NAPTR,
kDNSServiceClass_IN,
callback,
NULL);
DNSServiceProcessResult(sdRef);
DNSServiceRefDeallocate(sdRef);
In actual use, I found that there was an issue where the app would hang indefinitely if there were no results, so I ended up having to adjust my code to add a timeout on the result.
/*
Attempt to fetch the NAPTR from the stored server address. Since iOS will continue waiting
until told directly to stop (even if there is no result) we must set our own timeout on the
request (set to 5 seconds).
On success, the callback function is called. On timeout, the kSRVLookupComplete notification
is sent.
*/
- (void)attemptNAPTRFetch {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
DNSServiceRef sdRef;
DNSServiceErrorType err;
err = DNSServiceQueryRecord(&sdRef, 0, 0,
[server cStringUsingEncoding:[NSString defaultCStringEncoding]],
kDNSServiceType_NAPTR,
kDNSServiceClass_IN,
callback,
NULL);
// This stuff is necessary so we don't hang forever if there are no results
int dns_sd_fd = DNSServiceRefSockFD(sdRef);
int nfds = dns_sd_fd + 1;
fd_set readfds;
struct timeval tv;
int result;
int stopNow = 0;
int timeOut = 5; // Timeout in seconds
while (!stopNow) {
FD_ZERO(&readfds);
FD_SET(dns_sd_fd, &readfds);
tv.tv_sec = timeOut;
tv.tv_usec = 0;
result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
if (result > 0) {
if(FD_ISSET(dns_sd_fd, &readfds)) {
err = DNSServiceProcessResult(sdRef);
if (err != kDNSServiceErr_NoError){
NSLog(#"There was an error");
}
stopNow = 1;
}
}
else {
printf("select() returned %d errno %d %s\n", result, errno, strerror(errno));
if (errno != EINTR) {
stopNow = 1;
postNotification(kSRVLookupComplete, nil);
}
}
}
DNSServiceRefDeallocate(sdRef);
});
}
Then, for the callback:
static void callback(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char *fullname,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void *rdata,
uint32_t ttl,
void *context)
{
uint16_t order, pref;
char flag;
NSMutableString *service = [[NSMutableString alloc] init];
NSMutableString *replacement = [[NSMutableString alloc] init];
const char *data = (const char*)rdata;
order = data[1];
pref = data[3];
flag = data[5];
int i = 7;
while (data[i] != 0){
[service appendString:[NSString stringWithFormat:#"%c", data[i]]];
i++;
}
i += 2;
while(data[i] != 0){
if(data[i] >= 32 && data[i] <= 127)
[replacement appendString:[NSString stringWithFormat:#"%c", data[i]]];
else
[replacement appendString:#"."];
i++;
}
NSLog(#"\nOrder: %i\nPreference: %i\nFlag: %c\nService: %#\nReplacement: %#\n", order, pref, flag, service, replacement);
}
This seems to do the trick for me. You would of course do any other necessary work using all the parsed data in the callback or store the data somewhere to be used later.