#include "Python.h" #include #define SCNR_REACHABLE "SCNetworkIsReachable" static CFStringRef SCNR_Reachable = CFSTR(SCNR_REACHABLE); static SCNetworkReachabilityContext SCNR_Context = {0, NULL, NULL, NULL, NULL}; static void SCNR_callback(SCNetworkReachabilityRef target, SCNetworkConnectionFlags flags, void *tagString); static Boolean SCNR_reachable(SCNetworkConnectionFlags flags) { /* not reachable if it requires a non-automatic connection */ return ((flags & kSCNetworkFlagsReachable) && (!(flags & kSCNetworkFlagsConnectionRequired) || (flags & kSCNetworkFlagsConnectionAutomatic))); } /* XXX should have a way to cancel (e.g. on location detach) */ static void SCNR_schedule(CFStringRef tagString, SCNetworkReachabilityRef target) { SCNR_Context.info = (void *)tagString; SCNetworkReachabilitySetCallback(target, SCNR_callback, &SCNR_Context); SCNetworkReachabilityScheduleWithRunLoop(target, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); } static void SCNR_callback(SCNetworkReachabilityRef target, SCNetworkConnectionFlags flags, void *tagString) { if (SCNR_reachable(flags)) { CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), SCNR_Reachable, tagString, NULL, false); CFRelease((CFStringRef)tagString); } else { SCNR_schedule(tagString, target); } } static PyObject * SCNR_notify_when_reachable(PyObject *self, PyObject *args) { const char *hostname; const char *tag; if (!PyArg_ParseTuple(args, "ss", &hostname, &tag)) return NULL; SCNetworkConnectionFlags flags; if (SCNetworkCheckReachabilityByName(hostname, &flags) && SCNR_reachable(flags)) return PyBool_FromLong(0); SCNetworkReachabilityRef target = SCNetworkReachabilityCreateWithName(NULL, hostname); CFStringRef tagString = CFStringCreateWithCString(NULL, tag, kCFStringEncodingUTF8); SCNR_schedule(tagString, target); return PyBool_FromLong(1); } static PyMethodDef SCNetworkReachabilitymodule_methods[] = { {"notify_when_reachable", SCNR_notify_when_reachable, METH_VARARGS, "notify_when_reachable(hostname, tag) -> bool\n\n" "Deliver the SCNetworkIsReachable runloop notification with object tag\n" "when the host becomes reachable, or return false if it's currently\n" "reachable."}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initSCNetworkReachability(void) { PyObject *module = Py_InitModule("SCNetworkReachability", SCNetworkReachabilitymodule_methods); PyObject *dict = PyModule_GetDict(module); PyObject *reachable = PyString_FromString(SCNR_REACHABLE); PyDict_SetItemString(dict, SCNR_REACHABLE, reachable); Py_DECREF(reachable); }