static int splitFileObserver(TimeEventHandlerPtr event) { int is_split_on = *(int*)event->data; int file_exists = fileExists(splitTunnelingFile); if(is_split_on && file_exists) { splitTunneling = 1; } else if(is_split_on && !file_exists) { splitTunneling = 0; destroyNetworkList(); } else if(!is_split_on && file_exists) { int rc = parseSplitFile(splitTunnelingFile); if(rc < 0) { exit(1); } splitTunneling = 1; } event = scheduleTimeEvent(5, splitFileObserver, sizeof(splitTunneling), &splitTunneling); if(event == NULL) { do_log(L_ERROR, "Couldn't reschedule splitFileObserver"); exit(1); } return 1; }
static int dnsDelayedNotify(int error, GethostbynameRequestPtr request) { TimeEventHandlerPtr handler; if(error) handler = scheduleTimeEvent(0, dnsDelayedErrorNotifyHandler, sizeof(*request), request); else handler = scheduleTimeEvent(0, dnsDelayedDoneNotifyHandler, sizeof(*request), request); if(handler == NULL) { do_log(L_ERROR, "Couldn't schedule DNS notification.\n"); return -1; } return 1; }
static int dnsTimeoutHandler(TimeEventHandlerPtr event) { DnsQueryPtr query = *(DnsQueryPtr*)event->data; ObjectPtr object = query->object; int rc; /* People are reporting that this does happen. And I have no idea why. */ if(!queryInFlight(query)) { do_log(L_ERROR, "BUG: timing out martian query (%s, flags: 0x%x).\n", scrub(query->name->string), (unsigned)object->flags); return 1; } query->timeout = MAX(10, query->timeout * 2); if(query->timeout > dnsMaxTimeout) { abortObject(object, 501, internAtom("Timeout")); goto fail; } else { rc = sendQuery(query); if(rc < 0) { if(rc != -EWOULDBLOCK && rc != -EAGAIN && rc != -ENOBUFS) { abortObject(object, 501, internAtomError(-rc, "Couldn't send DNS query")); goto fail; } /* else let it timeout */ } query->timeout_handler = scheduleTimeEvent(query->timeout, dnsTimeoutHandler, sizeof(query), &query); if(query->timeout_handler == NULL) { do_log(L_ERROR, "Couldn't schedule DNS timeout handler.\n"); abortObject(object, 501, internAtom("Couldn't schedule DNS timeout handler")); goto fail; } return 1; } fail: removeQuery(query); object->flags &= ~OBJECT_INPROGRESS; if(query->inet4) releaseAtom(query->inet4); if(query->inet6) releaseAtom(query->inet6); free(query); releaseNotifyObject(object); return 1; }
static void maybe_free_chunks(int arenas, int force) { if (force || used_chunks >= CHUNKS(chunkHighMark)) { discardObjects(force, force); } if (arenas) free_chunk_arenas(); if (used_chunks >= CHUNKS(chunkLowMark) && !objectExpiryScheduled) { TimeEventHandlerPtr event; event = scheduleTimeEvent(1, discardObjectsHandler, 0, NULL); if (event) objectExpiryScheduled = 1; } }
int lingeringClose(int fd) { int rc; LingeringClosePtr l; rc = shutdown(fd, 1); if(rc < 0) { if(errno != ENOTCONN) { do_log_error(L_ERROR, errno, "Shutdown failed"); } else if(errno == EFAULT || errno == EBADF) { abort(); } CLOSE(fd); return 1; } l = malloc(sizeof(LingeringCloseRec)); if(l == NULL) goto fail; l->fd = fd; l->handler = NULL; l->timeout = NULL; l->timeout = scheduleTimeEvent(10, lingeringCloseTimeoutHandler, sizeof(LingeringClosePtr), &l); if(l->timeout == NULL) { free(l); goto fail; } l->handler = registerFdEvent(fd, POLLIN, lingeringCloseHandler, sizeof(LingeringClosePtr), &l); if(l->handler == NULL) { do_log(L_ERROR, "Couldn't schedule lingering close handler.\n"); /* But don't close -- the timeout will do its work. */ } return 1; fail: do_log(L_ERROR, "Couldn't schedule lingering close.\n"); CLOSE(fd); return 1; }
void initSplitTunneling(void) { int rc; if(!splitTunnelingFile || !splitTunnelingFile->string || strlen(splitTunnelingFile->string) == 0) { return; //Do not do split tunneling if file is not specified } if(!splitTunnelingDnsServer) { do_log(L_ERROR, "No splitTunnelingDnsServer provided for split tunneling\n"); exit(1); } if(psiphonServer && psiphonServer->string && strlen(psiphonServer->string) > 0) { memset(&psiphonServerAddr, 0, sizeof(psiphonServerAddr)); rc = inet_aton(psiphonServer->string, &psiphonServerAddr); if(!rc) { do_log(L_ERROR, "Couldn't parse psiphonServer IP\n"); exit(1); } } /* schedule splitFileObserver at this point*/ rc = 0; TimeEventHandlerPtr event = scheduleTimeEvent(-1, splitFileObserver, sizeof(rc), &rc); if(event == NULL) { do_log(L_ERROR, "Couldn't schedule splitFileObserver\n"); exit(1); } }
static int really_do_dns(AtomPtr name, ObjectPtr object) { int rc; DnsQueryPtr query; AtomPtr message = NULL; int id; AtomPtr a = NULL; if(a == NULL) { if(name == atomLocalhost || name == atomLocalhostDot) { char s[1 + sizeof(HostAddressRec)]; memset(s, 0, sizeof(s)); s[0] = DNS_A; s[1] = 4; s[2] = 127; s[3] = 0; s[4] = 0; s[5] = 1; a = internAtomN(s, 1 + sizeof(HostAddressRec)); if(a == NULL) { abortObject(object, 501, internAtom("Couldn't allocate address")); notifyObject(object); errno = ENOMEM; return -1; } } } if(a == NULL) { struct in_addr ina; rc = inet_aton(name->string, &ina); if(rc == 1) { char s[1 + sizeof(HostAddressRec)]; memset(s, 0, sizeof(s)); s[0] = DNS_A; s[1] = 4; memcpy(s + 2, &ina, 4); a = internAtomN(s, 1 + sizeof(HostAddressRec)); if(a == NULL) { abortObject(object, 501, internAtom("Couldn't allocate address")); notifyObject(object); errno = ENOMEM; return -1; } } } #ifdef HAVE_IPv6 if(a == NULL) a = rfc2732(name); #endif if(a) { object->headers = a; object->age = current_time.tv_sec; object->expires = current_time.tv_sec + 240; object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS); notifyObject(object); return 0; } rc = establishDnsSocket(); if(rc < 0) { do_log_error(L_ERROR, -rc, "Couldn't establish DNS socket.\n"); message = internAtomError(-rc, "Couldn't establish DNS socket"); goto fallback; } /* The id is used to speed up detecting replies to queries that are no longer current -- see dnsReplyHandler. */ id = (idSeed++) & 0xFFFF; query = malloc(sizeof(DnsQueryRec)); if(query == NULL) { do_log(L_ERROR, "Couldn't allocate DNS query.\n"); message = internAtom("Couldn't allocate DNS query"); goto fallback; } query->id = id; query->inet4 = NULL; query->inet6 = NULL; query->name = name; query->time = current_time.tv_sec; query->object = retainObject(object); query->timeout = 4; query->timeout_handler = NULL; query->next = NULL; query->timeout_handler = scheduleTimeEvent(query->timeout, dnsTimeoutHandler, sizeof(query), &query); if(query->timeout_handler == NULL) { do_log(L_ERROR, "Couldn't schedule DNS timeout handler.\n"); message = internAtom("Couldn't schedule DNS timeout handler"); goto free_fallback; } insertQuery(query); object->flags |= OBJECT_INPROGRESS; rc = sendQuery(query); if(rc < 0) { if(rc != -EWOULDBLOCK && rc != -EAGAIN && rc != -ENOBUFS) { object->flags &= ~OBJECT_INPROGRESS; message = internAtomError(-rc, "Couldn't send DNS query"); goto remove_fallback; } /* else let it timeout */ } releaseAtom(message); return 1; remove_fallback: removeQuery(query); free_fallback: releaseObject(query->object); cancelTimeEvent(query->timeout_handler); free(query); fallback: if(dnsUseGethostbyname >= 1) { releaseAtom(message); do_log(L_WARN, "Falling back on gethostbyname.\n"); return really_do_gethostbyname(name, object); } else { abortObject(object, 501, message); notifyObject(object); return 1; } }