Exemple #1
0
/* Here is the all important looping function that tells the event engine to
 * start up and begin processing events.  It will continue until all events have
 * been delivered (including new ones started from event handlers), or the
 * msec_timeout is reached, or a major error has occurred.  Use -1 if you don't
 * want to set a maximum time for it to run.  A timeout of 0 will return after 1
 * non-blocking loop.  The nsock loop can be restarted again after it returns.
 * For example you could do a series of 15 second runs, allowing you to do other
 * stuff between them */
enum nsock_loopstatus nsock_loop(nsock_pool nsp, int msec_timeout) {
  struct npool *ms = (struct npool *)nsp;
  struct timeval loop_timeout;
  int msecs_left;
  unsigned long loopnum = 0;
  enum nsock_loopstatus quitstatus = NSOCK_LOOP_ERROR;

  gettimeofday(&nsock_tod, NULL);

  if (msec_timeout < -1) {
    ms->errnum = EINVAL;
    return NSOCK_LOOP_ERROR;
  }
  TIMEVAL_MSEC_ADD(loop_timeout, nsock_tod, msec_timeout);
  msecs_left = msec_timeout;

  if (msec_timeout >= 0)
    nsock_log_debug("nsock_loop() started (timeout=%dms). %d events pending",
                    msec_timeout, ms->events_pending);
  else
    nsock_log_debug("nsock_loop() started (no timeout). %d events pending",
                    ms->events_pending);

  while (1) {
    if (ms->quit) {
      /* We've been asked to quit the loop through nsock_loop_quit. */
      ms->quit = 0;
      quitstatus = NSOCK_LOOP_QUIT;
      break;
    }

    if (ms->events_pending == 0) {
      /* if no events at all are pending, then none can be created until
       * we quit nsock_loop() -- so we do that now. */
      quitstatus = NSOCK_LOOP_NOEVENTS;
      break;
    }

    if (msec_timeout >= 0) {
      msecs_left = MAX(0, TIMEVAL_MSEC_SUBTRACT(loop_timeout, nsock_tod));
      if (msecs_left == 0 && loopnum > 0) {
        quitstatus = NSOCK_LOOP_TIMEOUT;
        break;
      }
    }

    if (nsock_engine_loop(ms, msecs_left) == -1) {
      quitstatus = NSOCK_LOOP_ERROR;
      break;
    }

    gettimeofday(&nsock_tod, NULL); /* we do this at end because there is one
                                     * at beginning of function */
    loopnum++;
  }

  return quitstatus;
}
Exemple #2
0
/* Create a new event structure -- must be deleted later with msevent_delete,
 * unless it returns NULL (failure).  NULL can be passed in for the msiod and
 * the userdata if not available */
msevent *msevent_new(mspool *nsp, enum nse_type type, msiod *msiod, int timeout_msecs,
                     nsock_ev_handler handler, void *userdata) {
  msevent *nse;

  /* Bring us up to date for the timeout calculation. */
  gettimeofday(&nsock_tod, NULL);

  if (msiod) {
    msiod->events_pending++;
    assert(msiod->state != NSIOD_STATE_DELETED);
  }

  /* First we check if one is available from the free list ... */
  nse = (msevent *)gh_list_pop(&nsp->free_events);
  if (!nse)
    nse = (msevent *)safe_malloc(sizeof(msevent));
  memset(nse, 0, sizeof(msevent));

  nse->id = get_new_event_id(nsp, type);
  nse->type = type;
  nse->status = NSE_STATUS_NONE;
#if HAVE_OPENSSL
  nse->sslinfo.ssl_desire = SSL_ERROR_NONE;
#endif
  if (type == NSE_TYPE_READ || type ==  NSE_TYPE_WRITE)
    filespace_init(&(nse->iobuf), 1024);
#if HAVE_PCAP

  if (type == NSE_TYPE_PCAP_READ) {
    mspcap *mp;
    int sz;

    assert(msiod != NULL);
    mp = (mspcap *)msiod->pcap;
    assert(mp);

    sz = mp->snaplen+1 + sizeof(nsock_pcap);
    filespace_init(&(nse->iobuf), sz);
  }
#endif

  if (timeout_msecs != -1) {
    assert(timeout_msecs >= 0);
    TIMEVAL_MSEC_ADD(nse->timeout, nsock_tod, timeout_msecs);
  }

  nse->iod = msiod;
  nse->handler = handler;
  nse->userdata = userdata;

  if (nse->iod == NULL)
    nsock_log_debug(nsp, "msevent_new (IOD #NULL) (EID #%li)", nse->id);
  else
    nsock_log_debug(nsp, "msevent_new (IOD #%li) (EID #%li)", nse->iod->id,
                    nse->id);
  return nse;
}
Exemple #3
0
static int handle_state_tcp_connected(struct npool *nsp, struct nevent *nse, void *udata) {
  struct proxy_chain_context *px_ctx = nse->iod->px_ctx;
  char *res;
  int reslen;

  res = nse_readbuf(nse, &reslen);

  /* TODO string check!! */
  if (!((reslen >= 15) && strstr(res, "200 OK"))) {
    struct proxy_node *node = px_ctx->px_current;

    nsock_log_debug("Connection refused from proxy %s", node->nodestr);
    return -EINVAL;
  }

  px_ctx->px_state = PROXY_STATE_HTTP_TUNNEL_ESTABLISHED;

  if (proxy_ctx_node_next(px_ctx) == NULL) {
    forward_event(nsp, nse, udata);
  } else {
    px_ctx->px_current = proxy_ctx_node_next(px_ctx);
    px_ctx->px_state   = PROXY_STATE_INITIAL;
    nsock_proxy_ev_dispatch(nsp, nse, udata);
  }
  return 0;
}
Exemple #4
0
/* Write some data to the socket.  If the write is not COMPLETED within
 * timeout_msecs , NSE_STATUS_TIMEOUT will be returned.  If you are supplying
 * NUL-terminated data, you can optionally pass -1 for datalen and nsock_write
 * will figure out the length itself */
nsock_event_id nsock_write(nsock_pool ms_pool, nsock_iod ms_iod,
          nsock_ev_handler handler, int timeout_msecs, void *userdata, const char *data, int datalen) {
  mspool *nsp = (mspool *)ms_pool;
  msiod *nsi = (msiod *)ms_iod;
  msevent *nse;
  char displaystr[256];

  nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
  assert(nse);

  nse->writeinfo.dest.ss_family = AF_UNSPEC;

  if (datalen < 0)
    datalen = (int)strlen(data);

    if (nsp->loglevel == NSOCK_LOG_DBG_ALL && datalen < 80) {
      memcpy(displaystr, ": ", 2);
      memcpy(displaystr + 2, data, datalen);
      displaystr[2 + datalen] = '\0';
      replacenonprintable(displaystr + 2, datalen, '.');
    } else {
      displaystr[0] = '\0';
    }

    nsock_log_debug(nsp, "Write request for %d bytes to IOD #%li EID %li [%s]%s",
                    datalen, nsi->id, nse->id, get_peeraddr_string(nsi), displaystr);

  fs_cat(&nse->iobuf, data, datalen);

  nsp_add_event(nsp, nse);

  return nse->id;
}
Exemple #5
0
void nsock_set_log_function(nsock_logger_t logger) {
  if (logger != NULL)
      NsockLogger = logger;
  else
      NsockLogger = nsock_stderr_logger;

  nsock_log_debug("Registered external logging function: %p", NsockLogger);
}
Exemple #6
0
nsock_event_id nsock_sendto(nsock_pool ms_pool, nsock_iod ms_iod, nsock_ev_handler handler, int timeout_msecs,
                            void *userdata, struct sockaddr *saddr, size_t sslen, unsigned short port, const char *data, int datalen) {
  mspool *nsp = (mspool *)ms_pool;
  msiod *nsi = (msiod *)ms_iod;
  msevent *nse;
  char displaystr[256];
  struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
#if HAVE_IPV6
  struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr;
#endif

  nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
  assert(nse);

  if (saddr->sa_family == AF_INET) {
    sin->sin_port = htons(port);
#if HAVE_SYS_UN_H
  } else if (saddr->sa_family == AF_INET6) {
#else
  } else {
#endif
    assert(saddr->sa_family == AF_INET6);
#if HAVE_IPV6
    sin6->sin6_port = htons(port);
#else
    fatal("IPv6 address passed to %s call, but nsock was not compiled w/IPv6 support", __func__);
#endif
  }

  assert(sslen <= sizeof(nse->writeinfo.dest));
  memcpy(&nse->writeinfo.dest, saddr, sslen);
  nse->writeinfo.destlen = sslen;

  assert(sslen <= sizeof(nse->iod->peer));
  memcpy(&nse->iod->peer, saddr, sslen);
  nse->iod->peerlen = sslen;

  if (datalen < 0)
    datalen = (int) strlen(data);

  if (nsp->loglevel == NSOCK_LOG_DBG_ALL && datalen < 80) {
    memcpy(displaystr, ": ", 2);
    memcpy(displaystr + 2, data, datalen);
    displaystr[2 + datalen] = '\0';
    replacenonprintable(displaystr + 2, datalen, '.');
  } else {
    displaystr[0] = '\0';
  }
  nsock_log_debug(nsp, "Sendto request for %d bytes to IOD #%li EID %li [%s]%s",
                  datalen, nsi->id, nse->id, get_peeraddr_string(nse->iod), displaystr);

  fs_cat(&nse->iobuf, data, datalen);

  nsp_add_event(nsp, nse);

  return nse->id;
}
Exemple #7
0
/* Free an msevent which was allocated with msevent_new, including all internal
 * resources.  Note -- we assume that nse->iod->events_pending (if it exists)
 * has ALREADY been decremented (done during msevent_dispatch_and_delete) -- so
 * remember to do this if you call msevent_delete() directly */
void msevent_delete(mspool *nsp, msevent *nse) {
  if (nse->iod == NULL)
    nsock_log_debug(nsp, "msevent_delete (IOD #NULL) (EID #%li)", nse->id);
  else
    nsock_log_debug(nsp, "msevent_delete (IOD #%li) (EID #%li)", nse->iod->id, nse->id);

  /* First free the IOBuf inside it if necessary */
  if (nse->type == NSE_TYPE_READ || nse->type ==  NSE_TYPE_WRITE) {
    fs_free(&nse->iobuf);
  }
  #if HAVE_PCAP
  if (nse->type == NSE_TYPE_PCAP_READ) {
    fs_free(&nse->iobuf);
    nsock_log_debug_all(nsp, "PCAP removed %lu", nse->id);
  }
  #endif

  /* Now we add the event back into the free pool */
  nse->event_done = 1;
}
Exemple #8
0
/* Adds an event to the appropriate nsp event list, handles housekeeping such as
 * adjusting the descriptor select/poll lists, registering the timeout value,
 * etc. */
void nsock_pool_add_event(struct npool *nsp, struct nevent *nse) {
  nsock_log_debug("NSE #%lu: Adding event (timeout in %ldms)",
                  nse->id,
                  (long)TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod));

  nsp->events_pending++;

  if (!nse->event_done && nse->timeout.tv_sec) {
    /* This event is expirable, add it to the queue */
    gh_heap_push(&nsp->expirables, &nse->expire);
  }

  /* Now we do the event type specific actions */
  switch (nse->type) {
    case NSE_TYPE_CONNECT:
    case NSE_TYPE_CONNECT_SSL:
      if (!nse->event_done) {
        assert(nse->iod->sd >= 0);
        socket_count_read_inc(nse->iod);
        socket_count_write_inc(nse->iod);
        update_events(nse->iod, nsp, EV_READ|EV_WRITE|EV_EXCEPT, EV_NONE);
      }
      iod_add_event(nse->iod, nse);
      break;

    case NSE_TYPE_READ:
      if (!nse->event_done) {
        assert(nse->iod->sd >= 0);
        socket_count_read_inc(nse->iod);
        update_events(nse->iod, nsp, EV_READ, EV_NONE);
#if HAVE_OPENSSL
        if (nse->iod->ssl)
          nse->sslinfo.ssl_desire = SSL_ERROR_WANT_READ;
#endif
      }
      iod_add_event(nse->iod, nse);
      break;

    case NSE_TYPE_WRITE:
      if (!nse->event_done) {
        assert(nse->iod->sd >= 0);
        socket_count_write_inc(nse->iod);
        update_events(nse->iod, nsp, EV_WRITE, EV_NONE);
#if HAVE_OPENSSL
        if (nse->iod->ssl)
          nse->sslinfo.ssl_desire = SSL_ERROR_WANT_WRITE;
#endif
      }
      iod_add_event(nse->iod, nse);
      break;

    case NSE_TYPE_TIMER:
      /* nothing to do */
      break;

#if HAVE_PCAP
    case NSE_TYPE_PCAP_READ: {
      mspcap *mp = (mspcap *)nse->iod->pcap;

      assert(mp);
      if (mp->pcap_desc >= 0) { /* pcap descriptor present */
        if (!nse->event_done) {
          socket_count_readpcap_inc(nse->iod);
          update_events(nse->iod, nsp, EV_READ, EV_NONE);
        }
        nsock_log_debug_all("PCAP NSE #%lu: Adding event to READ_EVENTS", nse->id);

        #if PCAP_BSD_SELECT_HACK
        /* when using BSD hack we must do pcap_next() after select().
         * Let's insert this pcap to bot queues, to selectable and nonselectable.
         * This will result in doing pcap_next_ex() just before select() */
        nsock_log_debug_all("PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id);
        #endif
      } else {
        /* pcap isn't selectable. Add it to pcap-specific queue. */
        nsock_log_debug_all("PCAP NSE #%lu: Adding event to PCAP_READ_EVENTS", nse->id);
      }
      iod_add_event(nse->iod, nse);
      break;
    }
#endif

    default:
      fatal("Unknown nsock event type (%d)", nse->type);
  }

  /* It can happen that the event already completed. In which case we can
   * already deliver it, even though we're probably not inside nsock_loop(). */
  if (nse->event_done) {
    event_dispatch_and_delete(nsp, nse, 1);
    update_first_events(nse);
    nevent_unref(nsp, nse);
  }
}
Exemple #9
0
/* Same as nsock_write except you can use a printf-style format and you can only use this for ASCII strings */
nsock_event_id nsock_printf(nsock_pool ms_pool, nsock_iod ms_iod,
          nsock_ev_handler handler, int timeout_msecs, void *userdata, char *format, ...) {
  mspool *nsp = (mspool *)ms_pool;
  msiod *nsi = (msiod *)ms_iod;
  msevent *nse;
  char buf[4096];
  char *buf2 = NULL;
  int res, res2;
  int strlength = 0;
  char displaystr[256];

  va_list ap;
  va_start(ap,format);

  nse = msevent_new(nsp, NSE_TYPE_WRITE, nsi, timeout_msecs, handler, userdata);
  assert(nse);

  res = Vsnprintf(buf, sizeof(buf), format, ap);
  va_end(ap);

  if (res != -1) {
    if (res > sizeof(buf)) {
      buf2 = (char * )safe_malloc(res + 16);
      res2 = Vsnprintf(buf2, sizeof(buf), format, ap);
      if (res2 == -1 || res2 > res) {
        free(buf2);
        buf2 = NULL;
      } else
        strlength = res2;
    } else {
      buf2 = buf;
      strlength = res;
    }
  }

  if (!buf2) {
    nse->event_done = 1;
    nse->status = NSE_STATUS_ERROR;
    nse->errnum = EMSGSIZE;
  } else {
    if (strlength == 0) {
      nse->event_done = 1;
      nse->status = NSE_STATUS_SUCCESS;
    } else {
      fs_cat(&nse->iobuf, buf2, strlength);
    }
  }

  if (nsp->loglevel == NSOCK_LOG_DBG_ALL && nse->status != NSE_STATUS_ERROR && strlength < 80) {
    memcpy(displaystr, ": ", 2);
    memcpy(displaystr + 2, buf2, strlength);
    displaystr[2 + strlength] = '\0';
    replacenonprintable(displaystr + 2, strlength, '.');
  } else {
    displaystr[0] = '\0';
  }

  nsock_log_debug(nsp, "Write request for %d bytes to IOD #%li EID %li [%s]%s",
                  strlength, nsi->id, nse->id, get_peeraddr_string(nsi), displaystr);

  if (buf2 != buf)
    free(buf2);

  nsp_add_event(nsp, nse);

  return nse->id;
}
Exemple #10
0
void nsock_set_log_function(nsock_pool nsp, nsock_logger_t logger) {
  mspool *ms = (mspool *)nsp;

  ms->logger = logger;
  nsock_log_debug(ms, "Registered external logging function: %p", logger);
}
Exemple #11
0
void nsock_set_loglevel(nsock_loglevel_t loglevel) {
  NsockLogLevel = loglevel;
  nsock_log_debug("Set log level to %s", nsock_loglevel2str(loglevel));
}