Beispiel #1
0
enum evcom_stream_state
evcom_stream_state (evcom_stream *stream)
{
  if (stream->recvfd < 0 && stream->sendfd && stream->flags == 0) {
    return EVCOM_INITIALIZED;
  }

  if (stream->recvfd < 0 && stream->sendfd < 0) return EVCOM_CLOSED;

  if (!CONNECTED(stream)) return EVCOM_CONNECTING;

  if (GOT_CLOSE(stream)) {
    if (READABLE(stream)) {
      return EVCOM_CONNECTED_RO;
    } else {
      return EVCOM_CLOSING;
    }
  }

  if (READABLE(stream) && WRITABLE(stream)) return EVCOM_CONNECTED_RW;

  if (WRITABLE(stream)) return EVCOM_CONNECTED_WO;

  if (READABLE(stream)) return EVCOM_CONNECTED_RO;

  return EVCOM_CLOSING;
}
Beispiel #2
0
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;
}
Beispiel #3
0
int
fix_gmode(sccs *s, int gflags)
{
	ser_t	d;

	/*
	 * Do not fix mode of symlink target, the file may not be 
	 * under BK control.
	 */
	if (S_ISLNK(s->mode)) return (0);

	if ((gflags&GET_EDIT) && WRITABLE(s))  return (0);
	if (!(gflags&GET_EDIT) && !WRITABLE(s))  return (0);

	d = sccs_top(s);
	if (MODE(s, d)) s->mode = MODE(s, d);
	unless (gflags&GET_EDIT) {
		s->mode &= ~0222;	/* turn off write mode */
	}

	if (chmod(s->gfile, s->mode)) return (1);
	return (0);
}
Beispiel #4
0
void
evcom_stream_attach (EV_P_ evcom_stream *stream)
{
  D_LOOP_SET(stream, EV_A);
  stream->flags |= EVCOM_ATTACHED;

  ev_timer_again(EV_A_ &stream->timeout_watcher);

  if (READABLE(stream)) {
    ev_io_start(EV_A_ &stream->read_watcher);
  }

  if (WRITABLE(stream)) {
    ev_io_start(EV_A_ &stream->write_watcher);
  }
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
/* 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;
}