static void _pkr_close(struct incoming_conn_state* ics, int log_level, const char* reason) { char rbuf[128]; char lbuf[128]; /* FIXME: Log more useful things about the connection. */ pk_log(PK_LOG_TUNNEL_CONNS | log_level, "%s; remote=%s; local=%s; hostname=%s; proto=%s; fd=%d", reason, in_addr_to_str((struct sockaddr*) &(ics->remote_addr), rbuf, 128), in_addr_to_str((struct sockaddr*) &(ics->local_addr), lbuf, 128), ics->hostname, known_protos[ics->parsed_as], ics->pkb->conn.sockfd); if (ics->pkb) { pkc_reset_conn(&(ics->pkb->conn), 0); pkm_free_be_conn(ics->pkb); } ics->parse_state = PARSE_FAILED; /* A horrible hack */ if (ics->unparsed_data != NULL) free(ics->unparsed_data); free(ics); }
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_log_fe_status(struct pk_manager* pkm) { int j, ddnsup_ago; struct pk_tunnel* fe; char printip[128]; char ddnsinfo[128]; PK_TRACE_FUNCTION; for (j = 0, fe = pkm->tunnels; j < pkm->tunnel_max; j++, fe++) { if (fe->ai.ai_addr && fe->fe_hostname) { if (NULL != in_addr_to_str(fe->ai.ai_addr, printip, 128)) { ddnsinfo[0] = '\0'; if (fe->last_ddnsup) { ddnsup_ago = time(0) - fe->last_ddnsup; sprintf(ddnsinfo, " (in DNS %us ago)", ddnsup_ago); } pk_log(PK_LOG_MANAGER_DEBUG, "Relay; status=0x%8.8x; errors=%d; info=%s%s%s%s%s%s%s%s", fe->conn.status, fe->error_count, printip, (fe->conn.status & FE_STATUS_REJECTED) ? " rejected": "", (fe->conn.status & FE_STATUS_WANTED) ? " wanted": "", (fe->conn.status & FE_STATUS_LAME) ? " lame": "", (fe->conn.status & FE_STATUS_IN_DNS) ? " in-DNS": "", (fe->conn.status & FE_STATUS_IS_FAST) ? " fast": "", (fe->conn.sockfd > 0) ? " live" : "", ddnsinfo); } } } }
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; }