int pklua_lua_socket_close(lua_State* L) { pk_log(PK_LOG_LUA_DEBUG, "pklua_lua_socket_close(%p)", L); int sockfd = _pklua_lua_socket_get_sockfd(L); if (sockfd > -1) PKS_close(sockfd); return 0; }
int pkr_conn_accepted_cb(int sockfd, void* void_pkm) { struct incoming_conn_state* ics; struct pk_manager* pkm = (struct pk_manager*) void_pkm; struct pk_backend_conn* pkb; socklen_t slen; char rbuf[128]; char lbuf[128]; PK_TRACE_FUNCTION; ics = malloc(sizeof(struct incoming_conn_state)); ics->pkm = pkm; ics->pkb = NULL; ics->tunnel = NULL; ics->hostname = NULL; ics->parsed_as = PROTO_UNKNOWN; ics->parse_state = PARSE_UNDECIDED; ics->created = pk_time(); ics->unparsed_data = NULL; slen = sizeof(ics->local_addr); getsockname(sockfd, (struct sockaddr*) &(ics->local_addr), &slen); slen = sizeof(ics->remote_addr); getpeername(sockfd, (struct sockaddr*) &(ics->remote_addr), &slen); pk_log(PK_LOG_TUNNEL_DATA, "Accepted; remote=%s; local=%s; fd=%d", in_addr_to_str((struct sockaddr*) &(ics->remote_addr), rbuf, 128), in_addr_to_str((struct sockaddr*) &(ics->local_addr), lbuf, 128), sockfd); /* Allocate a connection for this request or die... */ sprintf(lbuf, "!NEW:%d", ics->remote_addr.sin_port); if (NULL == (pkb = pkm_alloc_be_conn(pkm, NULL, lbuf))) { _pkr_close(ics, PK_LOG_ERROR, "BE alloc failed"); PKS_close(sockfd); return -1; } pkb->kite = NULL; pkb->conn.sockfd = sockfd; ics->pkb = pkb; set_non_blocking(sockfd); ev_io_init(&(pkb->conn.watch_r), pkr_new_conn_readable_cb, PKS_EV_FD(sockfd), EV_READ); pkb->conn.watch_r.data = (void *) ics; ev_io_start(pkm->loop, &(pkb->conn.watch_r)); return 0; }
void* pkb_run_blocker(void *void_pkblocker) { time_t last_check_world = 0; time_t last_check_tunnels = 0; struct pk_job job; struct pk_blocker* this = (struct pk_blocker*) void_pkblocker; struct pk_manager* pkm = this->manager; #if HAVE_LUA /* Initialize Lua state for this thread/blocker. */ if (pkm->lua != NULL) { this->lua = pklua_unlock_lua(pklua_get_locked_lua(pkm)); } #endif pk_log(PK_LOG_MANAGER_DEBUG, "Started blocking thread."); PK_HOOK(PK_HOOK_START_BLOCKER, 0, this, pkm); while (1) { pkb_get_job(&(pkm->blocking_jobs), &job); switch (job.job) { case PK_NO_JOB: break; case PK_CHECK_WORLD: if (time(0) >= last_check_world + pkm->housekeeping_interval_min) { pkm_reconfig_start((struct pk_manager*) job.ptr_data); if (PK_HOOK(PK_HOOK_CHECK_WORLD, 0, this, pkm)) { pkb_check_world((struct pk_manager*) job.ptr_data); pkb_check_tunnels((struct pk_manager*) job.ptr_data); last_check_world = last_check_tunnels = time(0); PK_HOOK(PK_HOOK_CHECK_WORLD, 1, this, pkm); } pkm_reconfig_stop((struct pk_manager*) job.ptr_data); } break; case PK_CHECK_FRONTENDS: if (time(0) >= last_check_tunnels + pkm->housekeeping_interval_min) { pkm_reconfig_start((struct pk_manager*) job.ptr_data); if (PK_HOOK(PK_HOOK_CHECK_TUNNELS, 0, this, pkm)) { pkb_check_tunnels((struct pk_manager*) job.ptr_data); last_check_tunnels = time(0); PK_HOOK(PK_HOOK_CHECK_TUNNELS, 1, this, pkm); } pkm_reconfig_stop((struct pk_manager*) job.ptr_data); } break; case PK_ACCEPT_LUA: #if HAVE_LUA pklua_socket_server_accepted(this->lua, job.int_data, job.ptr_data); #endif break; case PK_ACCEPT_FE: /* FIXME: Do something more useful here */ if (PKS_fail(PKS_close(job.int_data))) { }; break; case PK_QUIT: /* Put the job back in the queue, in case there are many workers */ pkb_add_job(&(pkm->blocking_jobs), PK_QUIT, 0, NULL); pk_log(PK_LOG_MANAGER_DEBUG, "Exiting blocking thread."); return NULL; } } }
void* pkb_tunnel_ping(void* void_fe) { struct pk_tunnel* fe = (struct pk_tunnel*) void_fe; struct timeval tv1, tv2, to; char buffer[1024], printip[1024]; int sockfd, bytes, want; PK_TRACE_FUNCTION; fe->priority = 0; in_addr_to_str(fe->ai.ai_addr, printip, 1024); if (pk_state.fake_ping) { fe->priority = rand() % 500; } else { gettimeofday(&tv1, NULL); to.tv_sec = pk_state.socket_timeout_s; to.tv_usec = 0; if ((0 > (sockfd = PKS_socket(fe->ai.ai_family, fe->ai.ai_socktype, fe->ai.ai_protocol))) || PKS_fail(PKS_setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *) &to, sizeof(to))) || PKS_fail(PKS_setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *) &to, sizeof(to))) || PKS_fail(PKS_connect(sockfd, fe->ai.ai_addr, fe->ai.ai_addrlen)) || PKS_fail(PKS_write(sockfd, PK_FRONTEND_PING, strlen(PK_FRONTEND_PING)))) { if (sockfd >= 0){ PKS_close(sockfd); } if (fe->error_count < 999) fe->error_count += 1; pk_log(PK_LOG_MANAGER_DEBUG, "Ping %s failed! (connect)", printip); sleep(2); /* We don't want to return first! */ return NULL; } /* Magic number: 116 bytes is the shortest response we expect. It is * still long enough to contain the X-PageKite-Overloaded marker, if * present at all. */ bytes = timed_read(sockfd, buffer, 116, 1000); buffer[116] = '\0'; want = strlen(PK_FRONTEND_PONG); if ((bytes < want) || (0 != strncmp(buffer, PK_FRONTEND_PONG, want))) { if (fe->error_count < 999) fe->error_count += 1; pk_log(PK_LOG_MANAGER_DEBUG, "Ping %s failed! (read=%d)", printip, bytes); sleep(2); /* We don't want to return first! */ return NULL; } PKS_close(sockfd); gettimeofday(&tv2, NULL); fe->priority = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000; if (strcasestr(buffer, PK_FRONTEND_OVERLOADED) != NULL) { fe->priority += 1; sleep(2); /* We don't want to return first! */ } } if (fe->conn.status & (FE_STATUS_WANTED|FE_STATUS_IS_FAST)) { /* Bias ping time to make old decisions a bit more sticky. We ignore * DNS though, to allow a bit of churn to spread the load around and * make sure new tunnels don't stay ignored forever. */ fe->priority /= 10; fe->priority *= 9; pk_log(PK_LOG_MANAGER_DEBUG, "Ping %s: %dms (biased)", printip, fe->priority); } else { /* Add artificial +/-5% jitter to ping results */ fe->priority *= ((rand() % 11) + 95); fe->priority /= 100; pk_log(PK_LOG_MANAGER_DEBUG, "Ping %s: %dms", printip, fe->priority); } PK_CHECK_MEMORY_CANARIES; return NULL; }
int http_get(const char* url, char* result_buffer, size_t maxlen) { char *urlparse, *hostname, *port, *path; struct addrinfo hints, *result, *rp; char request[10240], *bp; int sockfd, rlen, bytes, total_bytes; /* http://hostname:port/foo */ urlparse = strdup(url); hostname = urlparse+7; while (*hostname && *hostname == '/') hostname++; port = hostname; while (*port && *port != '/' && *port != ':') port++; if (*port == '/') { path = port; *path++ = '\0'; port = (url[5] == 's') ? "443" : "80"; } else { *port++ = '\0'; path = port; while (*path && *path != '/') path++; *path++ = '\0'; } rlen = snprintf(request, 10240, "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", path, hostname); if (10240 == rlen) { free(urlparse); return -1; } total_bytes = 0; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (0 == getaddrinfo(hostname, port, &hints, &result)) { for (rp = result; rp != NULL; rp = rp->ai_next) { if ((0 > (sockfd = PKS_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))) || PKS_fail(PKS_connect(sockfd, rp->ai_addr, rp->ai_addrlen)) || PKS_fail(PKS_write(sockfd, request, rlen))) { if (sockfd >= 0) PKS_close(sockfd); } else { total_bytes = 0; bp = result_buffer; do { bytes = timed_read(sockfd, bp, maxlen-(1+total_bytes), 1000); if (bytes > 0) { bp += bytes; total_bytes += bytes; } } while (bytes > 0); *bp = '\0'; PKS_close(sockfd); break; } } freeaddrinfo(result); } free(urlparse); return total_bytes; }