Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
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;
    }
  }
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;
}