Esempio n. 1
0
File: evcom.c Progetto: bernd/node
static int
stream_send__drain (evcom_stream *stream)
{
  if (stream->on_drain) {
    stream->on_drain(stream);
  }

  if (!GOT_CLOSE(stream)) {
    stream->send_action = stream_send__wait_for_buf;
    return OKAY;
  }

#if EVCOM_HAVE_GNUTLS
  if (SECURE(stream)) {
    stream->send_action = stream_send__gnutls_bye;
    return OKAY;
  }
#endif

  if (DUPLEX(stream)) {
    stream->send_action = stream_send__shutdown;
    return OKAY;
  }

  stream->send_action = stream_send__close_one;
  return OKAY;
}
Esempio n. 2
0
File: evcom.c Progetto: bernd/node
static ssize_t
pull (gnutls_transport_ptr_t data, void* buf, size_t len)
{
  evcom_stream *stream = (evcom_stream*)data;
  assert(SECURE(stream));

  return read(stream->recvfd, buf, len);
}
Esempio n. 3
0
File: evcom.c Progetto: bernd/node
static ssize_t
nosigpipe_push (gnutls_transport_ptr_t data, const void *buf, size_t len)
{
  evcom_stream *stream = (evcom_stream*)data;
  assert(SECURE(stream));

  return nosigpipe_stream_send(stream, buf, len);
}
Esempio n. 4
0
void closeInterface(Interface * interface) {
	assert(interface->open);

	interface->open = 0;

	while(fclose(interface->fp) && errno==EINTR);

	if(interface->commandList) freeList(interface->commandList);
	if(interface->bufferList) freeList(interface->bufferList);

	free(interface->outBuffer);

	SECURE("interface %i: closed\n",interface->num);
}
Esempio n. 5
0
void openAInterface(int fd, struct sockaddr * addr) {
	int i;

	for(i=0;i<interface_max_connections && interfaces[i].open;i++);

	if(i==interface_max_connections) {
		ERROR("Max Connections Reached!\n");
		while(close(fd) && errno==EINTR);
	}
	else {
		SECURE("interface %i: opened from ",i);
		switch(addr->sa_family) {
		case AF_INET:
			{
				char * host = inet_ntoa(
					((struct sockaddr_in *)addr)->
					sin_addr);
				if(host) { 
					SECURE("%s\n",host);
				}
				else {
					SECURE("error getting ipv4 address\n");
				}
			}
			break;
#ifdef HAVE_IPV6
		case AF_INET6:
			{
				char host[INET6_ADDRSTRLEN+1];
				memset(host,0,INET6_ADDRSTRLEN+1);
				if(inet_ntop(AF_INET6,(void *)
					&(((struct sockaddr_in6 *)addr)->
					sin6_addr),host,INET6_ADDRSTRLEN)) 
				{
					SECURE("%s\n",host);
				}
				else {
					SECURE("error getting ipv6 address\n");
				}
			}
			break;
#endif
		case AF_UNIX:
			SECURE("local connection\n");
			break;
		default:
			SECURE("unknown\n");
		}
		openInterface(&(interfaces[i]),fd);
	}
}
Esempio n. 6
0
File: evcom.c Progetto: bernd/node
void
evcom_stream_assign_fds (evcom_stream *stream, int recvfd, int sendfd)
{
  assert(recvfd >= 0);
  assert(sendfd >= 0);

  if (recvfd == sendfd) stream->flags |= EVCOM_DUPLEX;

  if (set_nonblock(recvfd) != 0) {
    evcom_perror("set_nonblock(recvfd)", errno);
  }

  if (set_nonblock(sendfd) != 0) {
    evcom_perror("set_nonblock(sendfd)", errno);
  }

#ifdef SO_NOSIGPIPE
  if (DUPLEX(stream)) {
    int flags = 1;
    int r = setsockopt(sendfd, SOL_SOCKET, SO_NOSIGPIPE, &flags, sizeof(flags));
    if (r < 0) {
      evcom_perror("setsockopt(SO_NOSIGPIPE)", errno);
    }
  }
#endif

  ev_io_set(&stream->read_watcher, recvfd, EV_READ);
  ev_io_set(&stream->write_watcher, sendfd, EV_WRITE);

  stream->recvfd = recvfd;
  stream->sendfd = sendfd;

  stream->send_action = stream__connection_established;
  stream->recv_action = stream__connection_established;

  stream->flags |= EVCOM_READABLE;
  stream->flags |= EVCOM_WRITABLE;

#if EVCOM_HAVE_GNUTLS
  if (SECURE(stream)) {
    gnutls_transport_set_lowat(stream->session, 0);
    gnutls_transport_set_push_function(stream->session, nosigpipe_push);
    gnutls_transport_set_pull_function(stream->session, pull);
    gnutls_transport_set_ptr2(stream->session, stream, stream);
  }
#endif
}
Esempio n. 7
0
File: evcom.c Progetto: 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;
}
Esempio n. 8
0
File: evcom.c Progetto: 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;
}
Esempio n. 9
0
File: evcom.c Progetto: bernd/node
static int
stream_send__gnutls_bye (evcom_stream *stream)
{
  assert(SECURE(stream));

  int r = gnutls_bye(stream->session, GNUTLS_SHUT_WR);

  if (r == GNUTLS_E_INTERRUPTED || r == GNUTLS_E_AGAIN) {
    assert(1 == gnutls_record_get_direction((stream)->session));
    assert(stream->send_action == stream_send__gnutls_bye);
    return AGAIN;
  }

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

  stream->flags &= ~EVCOM_WRITABLE;

  stream->send_action = stream_send__wait_for_eof;
  return OKAY;
}
Esempio n. 10
0
File: evcom.c Progetto: 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;
}
Esempio n. 11
0
File: evcom.c Progetto: 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;
}
Esempio n. 12
0
File: evcom.c Progetto: 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;
}