コード例 #1
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_reader_close (evcom_reader *reader)
{
  ev_io_start(D_LOOP_(reader) &reader->read_watcher);
  ev_feed_event(D_LOOP_(reader) &reader->read_watcher, EV_READ);

  close_asap((evcom_descriptor*)reader);
}
コード例 #2
0
ファイル: evcom.c プロジェクト: bernd/node
/**
 * Stops the server. Will not accept new connections.  Does not drop
 * existing connections.
 */
void
evcom_server_close (evcom_server *server)
{
  ev_io_start(D_LOOP_(server) &server->watcher);
  ev_feed_event(D_LOOP_(server) &server->watcher, EV_READ);

  close_asap((evcom_descriptor*)server);
}
コード例 #3
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_stream_detach (evcom_stream *stream)
{
  ev_io_stop(D_LOOP_(stream) &stream->write_watcher);
  ev_io_stop(D_LOOP_(stream) &stream->read_watcher);
  ev_timer_stop(D_LOOP_(stream) &stream->timeout_watcher);
  D_LOOP_SET(stream, NULL);
  stream->flags &= ~EVCOM_ATTACHED;
}
コード例 #4
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_stream_read_pause (evcom_stream *stream)
{
  stream->flags |= EVCOM_PAUSED;
  ev_timer_stop(D_LOOP_(stream) &stream->timeout_watcher);
  if (stream->recv_action == stream_recv__data) {
    ev_io_stop(D_LOOP_(stream) &stream->read_watcher);
    stream->recv_action = stream_recv__wait_for_resume;
  }
}
コード例 #5
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_stream_read_resume (evcom_stream *stream)
{
  stream->flags &= ~EVCOM_PAUSED;
  ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);
  if (stream->recv_action == stream_recv__wait_for_resume) {
    stream->recv_action = stream_recv__data;
  }
  if (ATTACHED(stream)) {
    ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);
    if (READABLE(stream)) ev_io_start(D_LOOP_(stream) &stream->read_watcher);
  }
}
コード例 #6
0
ファイル: evcom.c プロジェクト: bernd/node
static int
close_writer_asap (evcom_writer *writer)
{
  release_write_buffer(writer);
  ev_feed_event(D_LOOP_(writer) &writer->write_watcher, EV_WRITE);
  return close_asap((evcom_descriptor*)writer);
}
コード例 #7
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_server_detach (evcom_server *server)
{
  ev_io_stop (D_LOOP_(server) &server->watcher);
  D_LOOP_SET(server, NULL);
  server->flags &= ~EVCOM_ATTACHED;
}
コード例 #8
0
ファイル: evcom.c プロジェクト: bernd/node
/* Internal callback. called by stream->timeout_watcher */
static void
on_timeout (EV_P_ ev_timer *watcher, int revents)
{
  evcom_stream *stream = watcher->data;

#if EV_MULTIPLICITY
  assert(stream->loop == loop);
#endif
  assert(revents == EV_TIMEOUT);
  assert(watcher == &stream->timeout_watcher);

  if (PAUSED(stream)) {
    ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);
    return;
  }

  if (stream->on_timeout) stream->on_timeout(stream);

  // Hack to get error in Node on 'close' event.
  // should probably be made into a proper error code.
  stream->errorno = 1;

  ev_timer_stop(EV_A_ watcher);
  evcom_stream_force_close(stream);

  if (stream->on_close) stream->on_close(stream);
}
コード例 #9
0
ファイル: evcom.c プロジェクト: bernd/node
static inline void
stream__set_recv_closed (evcom_stream *stream)
{
  stream->flags &= ~EVCOM_READABLE;
  stream->recvfd = -1;
  stream->recv_action = NULL;
  ev_io_stop(D_LOOP_(stream) &stream->read_watcher);
}
コード例 #10
0
ファイル: evcom.c プロジェクト: bernd/node
static int
stream_recv__wait_for_resume (evcom_stream *stream)
{
  stream->flags |= EVCOM_PAUSED;
  ev_io_stop(D_LOOP_(stream) &stream->read_watcher);
  assert(stream->recv_action == stream_recv__wait_for_resume);
  return AGAIN;
}
コード例 #11
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_stream_reset_timeout (evcom_stream *stream, float timeout)
{
  stream->timeout_watcher.repeat = timeout;
  if (ATTACHED(stream)) {
    ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);
  }
}
コード例 #12
0
ファイル: evcom.c プロジェクト: bernd/node
static inline void
stream__set_send_closed (evcom_stream *stream)
{
  release_write_buffer(stream);
  stream->flags &= ~EVCOM_WRITABLE;
  stream->sendfd = -1;
  stream->send_action = NULL;
  ev_io_stop(D_LOOP_(stream) &stream->write_watcher);
}
コード例 #13
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_stream_close (evcom_stream *stream)
{
  stream->flags |= EVCOM_GOT_CLOSE;
  if (ATTACHED(stream)) {
    // start the watchers if attached.
    evcom_stream_attach(D_LOOP_(stream) stream); 
  }
}
コード例 #14
0
ファイル: evcom.c プロジェクト: bernd/node
static int
stream_send__wait_for_eof (evcom_stream *stream)
{
  if (READABLE(stream)) {
    ev_io_stop(D_LOOP_(stream) &stream->write_watcher);
    assert(stream->send_action == stream_send__wait_for_eof);
    return AGAIN;
  }

  stream->send_action = stream_send__close_one;
  return OKAY;
}
コード例 #15
0
ファイル: evcom.c プロジェクト: bernd/node
static int
stream_recv__wait_for_close (evcom_stream *stream)
{
  assert(!READABLE(stream));

  if (!WRITABLE(stream)) {
    stream->recv_action = stream_recv__close;
    return OKAY;
  }

  ev_io_stop(D_LOOP_(stream) &stream->read_watcher);
  return AGAIN;
}
コード例 #16
0
ファイル: evcom.c プロジェクト: bernd/node
/* Internal callback
 * Called by server->watcher.
 */
static int
accept_connections (evcom_descriptor *d)
{
  evcom_server *server = (evcom_server *)d;

  assert(LISTENING(server));

  /* accept as many connections as possible */
  evcom_stream *stream;
  while (server->fd >= 0 && (stream = accept_connection(server))) {
    evcom_stream_attach(D_LOOP_(server) stream);
  }

  return AGAIN;
}
コード例 #17
0
ファイル: evcom.c プロジェクト: bernd/node
static int
stream__connection_established (evcom_stream *stream)
{
  assert(!CONNECTED(stream));

#if EVCOM_HAVE_GNUTLS
  if (SECURE(stream)) {
    stream->send_action = stream__handshake;
    stream->recv_action = stream__handshake;
  } else
#endif
  {
    stream->flags |= EVCOM_CONNECTED;
    if (stream->on_connect) stream->on_connect(stream);

    stream->send_action = stream_send__data;
    stream->recv_action = stream_recv__data;
  }

  ev_io_start(D_LOOP_(stream) &stream->write_watcher);
  ev_io_start(D_LOOP_(stream) &stream->read_watcher);

  return OKAY;
}
コード例 #18
0
ファイル: evcom.c プロジェクト: bernd/node
static int
stream_send__wait_for_buf (evcom_stream *stream)
{
  if (evcom_queue_empty(&stream->out)) {
    if (GOT_CLOSE(stream)) {
      stream->send_action = stream_send__drain;
      return OKAY;
    }
    ev_io_stop(D_LOOP_(stream) &stream->write_watcher);
    return AGAIN;
  }

  stream->send_action = stream_send__data;
  return OKAY;
}
コード例 #19
0
ファイル: evcom.c プロジェクト: bernd/node
static int
writer_send (evcom_descriptor *d)
{
  evcom_writer* writer = (evcom_writer*) d;
  assert(writer->fd >= 0);

  while (!evcom_queue_empty(&writer->out)) {
    evcom_queue *q = evcom_queue_last(&writer->out);
    evcom_buf *buf = evcom_queue_data(q, evcom_buf, queue);

    ssize_t sent = write(writer->fd, buf->base + buf->written,
        buf->len - buf->written);

    if (sent < 0) {
      switch (errno) {
        case ECONNRESET:
        case EPIPE:
          return close_writer_asap(writer);

        case EINTR:
        case EAGAIN:
          sent = 0;
          return AGAIN;

        default:
          writer->errorno = errno;
          evcom_perror("send()", writer->errorno);
          return close_writer_asap(writer);
      }
    }
    assert(sent >= 0);

    buf->written += sent;

    if (buf->written == buf->len) {
      evcom_queue_remove(q);
      if (buf->release) buf->release(buf);
    }
  }

  if (GOT_CLOSE(writer)) {
    assert(evcom_queue_empty(&writer->out));
    return close_writer_asap(writer);
  } else {
    ev_io_stop(D_LOOP_(writer) &writer->write_watcher);
    return AGAIN;
  }
}
コード例 #20
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_writer_write (evcom_writer* writer, const char* buf, size_t len)
{
  assert(writer->fd >= 0);

  ssize_t sent = 0;

  if (evcom_queue_empty(&writer->out)) {
    sent = write(writer->fd, buf, len);

    if (sent < 0) {
      switch (errno) {
        case ECONNRESET:
        case EPIPE:
          goto close;

        case EINTR:
        case EAGAIN:
          sent = 0;
          break;

        default:
          writer->errorno = errno;
          evcom_perror("send()", writer->errorno);
          goto close;
      }
    }
  } /* TODO else { memcpy to last buffer on head } */

  assert(sent >= 0);
  if ((size_t)sent == len) return; /* sent the whole buffer */

  len -= sent;
  buf += sent;

  evcom_buf *b = evcom_buf_new(buf, len);
  evcom_queue_insert_head(&writer->out, &b->queue);
  b->written = 0;

  assert(writer->fd >= 0);
  ev_io_start(D_LOOP_(writer) &writer->write_watcher);
  return;

close:
  close_writer_asap(writer);
}
コード例 #21
0
ファイル: evcom.c プロジェクト: bernd/node
static int
stream__handshake (evcom_stream *stream)
{
  assert(SECURE(stream));

  int r = gnutls_handshake(stream->session);

  if (gnutls_error_is_fatal(r)) {
    stream->gnutls_errorno = r;
    stream->send_action = stream_send__close;
    stream->recv_action = stream_recv__close;
    return OKAY;
  }

  ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);

  if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
    if (0 == gnutls_record_get_direction((stream)->session)) {
      ev_io_start(D_LOOP_(stream) &(stream)->read_watcher); 
      ev_io_stop(D_LOOP_(stream) &(stream)->write_watcher); 
    } else {
      ev_io_stop(D_LOOP_(stream) &(stream)->read_watcher); 
      ev_io_start(D_LOOP_(stream) &(stream)->write_watcher);
    }
    assert(stream->recv_action == stream__handshake);
    assert(stream->send_action == stream__handshake);
    return AGAIN;
  }

  assert(!CONNECTED(stream));
  stream->flags |= EVCOM_CONNECTED;
  if (stream->on_connect) stream->on_connect(stream);

  /* evcom_stream_force_close might have been called. */
  if (stream->recvfd >= 0 && stream->sendfd >= 0) {
    ev_io_start(D_LOOP_(stream) &stream->read_watcher);
    ev_io_start(D_LOOP_(stream) &stream->write_watcher);

    stream->send_action = stream_send__data;
    stream->recv_action = stream_recv__data;
  }

  return OKAY;
}
コード例 #22
0
ファイル: evcom.c プロジェクト: blaine/node
/* Internal callback. called by stream->timeout_watcher */
static void
on_timeout (EV_P_ ev_timer *watcher, int revents)
{
  evcom_stream *stream = watcher->data;

#if EV_MULTIPLICITY
  assert(stream->loop == loop);
#endif
  assert(revents == EV_TIMEOUT);
  assert(watcher == &stream->timeout_watcher);

  if (PAUSED(stream)) {
    ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);
    return;
  }

  if (stream->on_timeout) stream->on_timeout(stream);

  evcom_stream_force_close(stream);

  if (stream->on_close) stream->on_close(stream);
}
コード例 #23
0
ファイル: evcom.c プロジェクト: bernd/node
/* Returns the number of bytes flushed to the buffer */
ssize_t
evcom_stream_write (evcom_stream *stream, const char *str, size_t len)
{
  if (!WRITABLE(stream) || GOT_CLOSE(stream)) {
    assert(0 && "Do not write to a closed stream");
    return -1;
  }

  ssize_t sent = 0;

  if ( stream->send_action == stream_send__wait_for_buf
    && evcom_queue_empty(&stream->out)
     ) 
  {
    assert(CONNECTED(stream));
#if EVCOM_HAVE_GNUTLS
    if (SECURE(stream)) {
      sent = gnutls_record_send(stream->session, str, len);

      if (gnutls_error_is_fatal(sent)) {
        stream->gnutls_errorno = sent;
        goto close;
      }
    } else
#endif // EVCOM_HAVE_GNUTLS
    {
      /* TODO use writev() here? */
      sent = nosigpipe_stream_send(stream, str, len);
    }

    if (sent < 0) {
      switch (errno) {
        case EPIPE:
          goto close;

        case EINTR:
        case EAGAIN:
          sent = 0;
          break;

        default:
          stream->errorno = errno;
          evcom_perror("send()", stream->errorno);
          goto close;
      }
    }
  } /* TODO else { memcpy to last buffer on head } */

  assert(sent >= 0);
  if ((size_t)sent == len) return sent; /* sent the whole buffer */

  len -= sent;
  str += sent;

  evcom_buf *b = evcom_buf_new(str, len);
  evcom_queue_insert_head(&stream->out, &b->queue);
  b->written = 0;

  assert(stream->sendfd >= 0);

  if (ATTACHED(stream)) {
    ev_io_start(D_LOOP_(stream) &stream->write_watcher);
  }
  return sent;

close:
  stream->send_action = stream_send__close;
  stream->recv_action = stream_recv__close;
  if (ATTACHED(stream)) {
    ev_io_start(D_LOOP_(stream) &stream->write_watcher);
  }
  return -1;
}
コード例 #24
0
ファイル: evcom.c プロジェクト: bernd/node
static int
stream_send__data (evcom_stream *stream)
{
  ssize_t sent;

  while (!evcom_queue_empty(&stream->out)) {
    assert(WRITABLE(stream));

    evcom_queue *q = evcom_queue_last(&stream->out);
    evcom_buf *buf = evcom_queue_data(q, evcom_buf, queue);

#if EVCOM_HAVE_GNUTLS
    if (SECURE(stream)) {
      sent = gnutls_record_send(stream->session,
          buf->base + buf->written,
          buf->len - buf->written);

      if (sent == GNUTLS_E_INTERRUPTED || sent == GNUTLS_E_AGAIN) {
        if (0 == gnutls_record_get_direction((stream)->session)) {
          fprintf(stderr, "(evcom) gnutls send: unexpected switch direction!\n");
          ev_io_start(D_LOOP_(stream) &(stream)->read_watcher); 
          ev_io_stop(D_LOOP_(stream) &(stream)->write_watcher);
        }
        return AGAIN;
      }

      if (gnutls_error_is_fatal(sent)) {
        stream->gnutls_errorno = sent;
        stream->send_action = stream_send__close;
        return OKAY;
      }
    } else
#endif // EVCOM_HAVE_GNUTLS
    {
      /* TODO use writev() here? */
      sent = nosigpipe_stream_send(stream,
          buf->base + buf->written,
          buf->len - buf->written);
    }

    if (sent <= 0) {
      switch (errno) {
        case EAGAIN:
        case EINTR:
          assert(stream->send_action == stream_send__data);
          return AGAIN;

        default:
          stream->errorno = errno;
          evcom_perror("send()", errno);
          /* pass through */
        case EPIPE:
          stream->send_action = stream_send__close;
          return OKAY;
      }
    }

    ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);

    assert(sent >= 0);

    buf->written += sent;

    if (buf->written == buf->len) {
      evcom_queue_remove(q);
      if (buf->release) buf->release(buf);
    }
  }

  assert(evcom_queue_empty(&stream->out));

  stream->send_action = stream_send__drain;
  return OKAY;
}
コード例 #25
0
ファイル: evcom.c プロジェクト: bernd/node
static int
stream_recv__data (evcom_stream *stream)
{
  char buf[EVCOM_CHUNKSIZE];
  size_t buf_size = EVCOM_CHUNKSIZE;
  ssize_t recved;

  while (READABLE(stream)) {
    assert(CONNECTED(stream));

    if (PAUSED(stream)) {
      stream->recv_action = stream_recv__wait_for_resume;
      return OKAY;
    }


#if EVCOM_HAVE_GNUTLS
    if (SECURE(stream)) {
      recved = gnutls_record_recv(stream->session, buf, buf_size);

      if (gnutls_error_is_fatal(recved)) {
        stream->gnutls_errorno = recved;
        stream->recv_action = stream_recv__close;
        return OKAY;
      }

      if (recved == GNUTLS_E_INTERRUPTED || recved == GNUTLS_E_AGAIN) {
        if (1 == gnutls_record_get_direction((stream)->session)) {
          fprintf(stderr, "(evcom) gnutls recv: unexpected switch direction!\n");
          ev_io_stop(D_LOOP_(stream) &(stream)->read_watcher); 
          ev_io_start(D_LOOP_(stream) &(stream)->write_watcher);
        }
        return AGAIN;
      }

      /* A server may also receive GNUTLS_E_REHANDSHAKE when a client has
       * initiated a andshake. In that case the server can only initiate a
       * handshake or terminate the connection. */
      if (recved == GNUTLS_E_REHANDSHAKE) {
        assert(WRITABLE(stream));
        stream->recv_action = stream__handshake;
        stream->send_action = stream__handshake;
        return OKAY;
      }
    } else 
#endif /* EVCOM_HAVE_GNUTLS */
    {
      recved = read(stream->recvfd, buf, buf_size);
    }

    if (recved < 0) {
      if (errno == EAGAIN || errno == EINTR) {
        assert(stream->recv_action == stream_recv__data);
        return AGAIN;
      } 
      
      if (errno != ECONNRESET) {
        evcom_perror("recv()", stream->errorno);
      }

      stream->errorno = errno;
      stream->recv_action = stream_recv__close;
      return OKAY;
    }

    ev_timer_again(D_LOOP_(stream) &stream->timeout_watcher);

    assert(recved >= 0);

    if (recved == 0) {
      stream->flags &= ~EVCOM_READABLE;
      ev_io_stop(D_LOOP_(stream) &stream->read_watcher);
      stream->recv_action = stream_recv__wait_for_close;
    }

    /* NOTE: EOF is signaled with recved == 0 on callback */
    if (stream->on_read) stream->on_read(stream, buf, recved);

    if (recved == 0) {
      return OKAY;
    }
  }
  return AGAIN;
}
コード例 #26
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_reader_detach (evcom_reader *reader)
{
  ev_io_stop(D_LOOP_(reader) &reader->read_watcher);
  D_LOOP_SET(reader, NULL);
}
コード例 #27
0
ファイル: evcom.c プロジェクト: bernd/node
void
evcom_writer_detach (evcom_writer* writer)
{
  ev_io_stop(D_LOOP_(writer) &writer->write_watcher);
  D_LOOP_SET(writer, NULL);
}