Blame tests/eagain-common.h

Packit 549fdc
#include <errno.h>
Packit 549fdc
Packit 549fdc
#define min(x,y) ((x)<(y)?(x):(y))
Packit 549fdc
Packit 549fdc
extern const char *side;
Packit 549fdc
Packit 549fdc
#define HANDSHAKE_EXPECT(c, s, clierr, serverr) \
Packit 549fdc
  sret = cret = GNUTLS_E_AGAIN; \
Packit 549fdc
  do \
Packit 549fdc
    { \
Packit 549fdc
      if (cret == GNUTLS_E_AGAIN) \
Packit 549fdc
	{ \
Packit 549fdc
	  side = "client"; \
Packit 549fdc
	  cret = gnutls_handshake (c); \
Packit 549fdc
	  if (cret == GNUTLS_E_INTERRUPTED) cret = GNUTLS_E_AGAIN; \
Packit 549fdc
	} \
Packit 549fdc
      if (sret == GNUTLS_E_AGAIN) \
Packit 549fdc
	{ \
Packit 549fdc
	  side = "server"; \
Packit 549fdc
	  sret = gnutls_handshake (s); \
Packit 549fdc
	  if (sret == GNUTLS_E_INTERRUPTED) sret = GNUTLS_E_AGAIN; \
Packit 549fdc
	} \
Packit 549fdc
    } \
Packit 549fdc
  while ((cret == GNUTLS_E_AGAIN || (cret == 0 && sret == GNUTLS_E_AGAIN)) && (sret == GNUTLS_E_AGAIN || (sret == 0 && cret == GNUTLS_E_AGAIN))); \
Packit 549fdc
  if (cret != clierr || sret != serverr) \
Packit 549fdc
    { \
Packit 549fdc
      fprintf(stderr, "client[%d]: %s\n", cret, gnutls_strerror(cret)); \
Packit 549fdc
      fprintf(stderr, "server[%d]: %s\n", sret, gnutls_strerror(sret)); \
Packit 549fdc
      fail("Handshake failed\n"); \
Packit 549fdc
      exit(1); \
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
#define HANDSHAKE(c, s) \
Packit 549fdc
  HANDSHAKE_EXPECT(c,s,0,0)
Packit 549fdc
Packit 549fdc
#define HANDSHAKE_DTLS_EXPECT(c, s, clierr, serverr) \
Packit 549fdc
  sret = cret = GNUTLS_E_AGAIN; \
Packit 549fdc
  do \
Packit 549fdc
    { \
Packit 549fdc
      if (cret == GNUTLS_E_LARGE_PACKET) \
Packit 549fdc
	{ \
Packit 549fdc
	  unsigned int mtu = gnutls_dtls_get_mtu(s); \
Packit 549fdc
	  gnutls_dtls_set_mtu(s, mtu/2); \
Packit 549fdc
	} \
Packit 549fdc
      if (cret < 0 && gnutls_error_is_fatal(cret) == 0) \
Packit 549fdc
	{ \
Packit 549fdc
	  side = "client"; \
Packit 549fdc
	  cret = gnutls_handshake (c); \
Packit 549fdc
	} \
Packit 549fdc
      if (sret == GNUTLS_E_LARGE_PACKET) \
Packit 549fdc
	{ \
Packit 549fdc
	  unsigned int mtu = gnutls_dtls_get_mtu(s); \
Packit 549fdc
	  gnutls_dtls_set_mtu(s, mtu/2); \
Packit 549fdc
	} \
Packit 549fdc
      if (sret < 0 && gnutls_error_is_fatal(sret) == 0) \
Packit 549fdc
	{ \
Packit 549fdc
	  side = "server"; \
Packit 549fdc
	  sret = gnutls_handshake (s); \
Packit 549fdc
	} \
Packit 549fdc
    } \
Packit 549fdc
  while (((gnutls_error_is_fatal(cret) == 0 && gnutls_error_is_fatal(sret) == 0)) && (cret < 0 || sret < 0)); \
Packit 549fdc
  if (cret != clierr || sret != serverr) \
Packit 549fdc
    { \
Packit 549fdc
      fprintf(stderr, "client: %s\n", gnutls_strerror(cret)); \
Packit 549fdc
      fprintf(stderr, "server: %s\n", gnutls_strerror(sret)); \
Packit 549fdc
      fail("%s:%d: Handshake failed\n", __func__, __LINE__); \
Packit 549fdc
      exit(1); \
Packit 549fdc
    }
Packit 549fdc
Packit 549fdc
#define HANDSHAKE_DTLS(c, s) \
Packit 549fdc
  HANDSHAKE_DTLS_EXPECT(c,s,0,0)
Packit 549fdc
Packit 549fdc
#define HANDSHAKE(c, s) \
Packit 549fdc
  HANDSHAKE_EXPECT(c,s,0,0)
Packit 549fdc
Packit 549fdc
#define TRANSFER2(c, s, msg, msglen, buf, buflen, retry_send_with_null) \
Packit 549fdc
  side = "client"; \
Packit 549fdc
  ret = record_send_loop (c, msg, msglen, retry_send_with_null); \
Packit 549fdc
  \
Packit 549fdc
  if (ret < 0) fail ("client send error: %s\n", gnutls_strerror (ret)); \
Packit 549fdc
  \
Packit 549fdc
  do \
Packit 549fdc
    { \
Packit 549fdc
      do \
Packit 549fdc
	{ \
Packit 549fdc
	  side = "server"; \
Packit 549fdc
	  ret = gnutls_record_recv (s, buf, buflen); \
Packit 549fdc
	} \
Packit 549fdc
      while(ret == GNUTLS_E_AGAIN); \
Packit 549fdc
      if (ret == 0) \
Packit 549fdc
	fail ("server: didn't receive any data\n"); \
Packit 549fdc
      else if (ret < 0) \
Packit 549fdc
	{ \
Packit 549fdc
	  fail ("server: error: %s\n", gnutls_strerror (ret)); \
Packit 549fdc
	} \
Packit 549fdc
      else \
Packit 549fdc
	{ \
Packit 549fdc
	  transferred += ret; \
Packit 549fdc
	} \
Packit 549fdc
      side = "server"; \
Packit 549fdc
      ns = record_send_loop (server, msg, msglen, retry_send_with_null); \
Packit 549fdc
      if (ns < 0) fail ("server send error: %s\n", gnutls_strerror (ret)); \
Packit 549fdc
      do \
Packit 549fdc
	{ \
Packit 549fdc
	  side = "client"; \
Packit 549fdc
	  ret = gnutls_record_recv (client, buf, buflen); \
Packit 549fdc
	} \
Packit 549fdc
      while(ret == GNUTLS_E_AGAIN); \
Packit 549fdc
      if (ret == 0) \
Packit 549fdc
	{ \
Packit 549fdc
	  fail ("client: Peer has closed the TLS connection\n"); \
Packit 549fdc
	} \
Packit 549fdc
      else if (ret < 0) \
Packit 549fdc
	{ \
Packit 549fdc
	  if (debug) \
Packit 549fdc
	    fputs ("!", stdout); \
Packit 549fdc
	  fail ("client: Error: %s\n", gnutls_strerror (ret)); \
Packit 549fdc
	} \
Packit 549fdc
      else \
Packit 549fdc
	{ \
Packit 549fdc
	  if (msglen != ret || memcmp (buf, msg, msglen) != 0) \
Packit 549fdc
	    { \
Packit 549fdc
	      fail ("client: Transmitted data do not match\n"); \
Packit 549fdc
	    } \
Packit 549fdc
	  /* echo back */ \
Packit 549fdc
	  side = "client"; \
Packit 549fdc
	  ns = record_send_loop (client, buf, msglen, retry_send_with_null); \
Packit 549fdc
	  if (ns < 0) fail ("client send error: %s\n", gnutls_strerror (ret)); \
Packit 549fdc
	  transferred += ret; \
Packit 549fdc
	  if (debug) \
Packit 549fdc
	    fputs (".", stdout); \
Packit 549fdc
	} \
Packit 549fdc
    } \
Packit 549fdc
  while (transferred < 70000)
Packit 549fdc
Packit 549fdc
#define TRANSFER(c, s, msg, msglen, buf, buflen) \
Packit 549fdc
  TRANSFER2(c, s, msg, msglen, buf, buflen, 0); \
Packit 549fdc
  TRANSFER2(c, s, msg, msglen, buf, buflen, 1)
Packit 549fdc
Packit 549fdc
static char to_server[64 * 1024];
Packit 549fdc
static size_t to_server_len = 0;
Packit 549fdc
Packit 549fdc
static char to_client[64 * 1024];
Packit 549fdc
static size_t to_client_len = 0;
Packit 549fdc
Packit 549fdc
#ifdef RANDOMIZE
Packit 549fdc
#define RETURN_RND_EAGAIN(session) \
Packit 549fdc
  static unsigned char rnd = 0; \
Packit 549fdc
  if (rnd++ % 2 == 0) \
Packit 549fdc
    { \
Packit 549fdc
      gnutls_transport_set_errno (session, EAGAIN); \
Packit 549fdc
      return -1; \
Packit 549fdc
    }
Packit 549fdc
#else
Packit 549fdc
#define RETURN_RND_EAGAIN(session)
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
#ifndef IGNORE_PUSH
Packit 549fdc
static ssize_t
Packit 549fdc
client_push(gnutls_transport_ptr_t tr, const void *data, size_t len)
Packit 549fdc
{
Packit 549fdc
	size_t newlen;
Packit 549fdc
	RETURN_RND_EAGAIN(tr);
Packit 549fdc
Packit 549fdc
	len = min(len, sizeof(to_server) - to_server_len);
Packit 549fdc
Packit 549fdc
	newlen = to_server_len + len;
Packit 549fdc
	memcpy(to_server + to_server_len, data, len);
Packit 549fdc
	to_server_len = newlen;
Packit 549fdc
#ifdef EAGAIN_DEBUG
Packit 549fdc
	fprintf(stderr, "eagain: pushed %d bytes to server (avail: %d)\n",
Packit 549fdc
		(int) len, (int) to_server_len);
Packit 549fdc
#endif
Packit 549fdc
	return len;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
static ssize_t
Packit 549fdc
client_pull(gnutls_transport_ptr_t tr, void *data, size_t len)
Packit 549fdc
{
Packit 549fdc
	RETURN_RND_EAGAIN(tr);
Packit 549fdc
Packit 549fdc
	if (to_client_len == 0) {
Packit 549fdc
#ifdef EAGAIN_DEBUG
Packit 549fdc
		fprintf(stderr,
Packit 549fdc
			"eagain: Not enough data by server (asked for: %d, have: %d)\n",
Packit 549fdc
			(int) len, (int) to_client_len);
Packit 549fdc
#endif
Packit 549fdc
		gnutls_transport_set_errno((gnutls_session_t) tr, EAGAIN);
Packit 549fdc
		return -1;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	len = min(len, to_client_len);
Packit 549fdc
Packit 549fdc
	memcpy(data, to_client, len);
Packit 549fdc
Packit 549fdc
	memmove(to_client, to_client + len, to_client_len - len);
Packit 549fdc
	to_client_len -= len;
Packit 549fdc
#ifdef EAGAIN_DEBUG
Packit 549fdc
	fprintf(stderr, "eagain: pulled %d bytes by client (avail: %d)\n",
Packit 549fdc
		(int) len, (int) to_client_len);
Packit 549fdc
#endif
Packit 549fdc
	return len;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
static ssize_t
Packit 549fdc
server_pull(gnutls_transport_ptr_t tr, void *data, size_t len)
Packit 549fdc
{
Packit 549fdc
	//success ("server_pull len %d has %d\n", len, to_server_len);
Packit 549fdc
	RETURN_RND_EAGAIN(tr);
Packit 549fdc
Packit 549fdc
	if (to_server_len == 0) {
Packit 549fdc
#ifdef EAGAIN_DEBUG
Packit 549fdc
		fprintf(stderr,
Packit 549fdc
			"eagain: Not enough data by client (asked for: %d, have: %d)\n",
Packit 549fdc
			(int) len, (int) to_server_len);
Packit 549fdc
#endif
Packit 549fdc
		gnutls_transport_set_errno((gnutls_session_t) tr, EAGAIN);
Packit 549fdc
		return -1;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	len = min(len, to_server_len);
Packit 549fdc
#ifdef EAGAIN_DEBUG
Packit 549fdc
	fprintf(stderr, "eagain: pulled %d bytes by server (avail: %d)\n",
Packit 549fdc
		(int) len, (int) to_server_len);
Packit 549fdc
#endif
Packit 549fdc
	memcpy(data, to_server, len);
Packit 549fdc
Packit 549fdc
	memmove(to_server, to_server + len, to_server_len - len);
Packit 549fdc
	to_server_len -= len;
Packit 549fdc
Packit 549fdc
	return len;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
#ifndef IGNORE_PUSH
Packit 549fdc
static ssize_t
Packit 549fdc
server_push(gnutls_transport_ptr_t tr, const void *data, size_t len)
Packit 549fdc
{
Packit 549fdc
	size_t newlen;
Packit 549fdc
	RETURN_RND_EAGAIN(tr);
Packit 549fdc
Packit 549fdc
//  hexprint (data, len);
Packit 549fdc
Packit 549fdc
	len = min(len, sizeof(to_client) - to_client_len);
Packit 549fdc
Packit 549fdc
	newlen = to_client_len + len;
Packit 549fdc
	memcpy(to_client + to_client_len, data, len);
Packit 549fdc
	to_client_len = newlen;
Packit 549fdc
#ifdef EAGAIN_DEBUG
Packit 549fdc
	fprintf(stderr, "eagain: pushed %d bytes to client (avail: %d)\n",
Packit 549fdc
		(int) len, (int) to_client_len);
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
Packit 549fdc
#ifdef SERVER_PUSH_ADD
Packit 549fdc
	SERVER_PUSH_ADD
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
	return len;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
/* inline is used to avoid a gcc warning if used in mini-eagain */
Packit 549fdc
inline static int server_pull_timeout_func(gnutls_transport_ptr_t ptr,
Packit 549fdc
					   unsigned int ms)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
Packit 549fdc
	if (to_server_len > 0)
Packit 549fdc
		ret = 1;	/* available data */
Packit 549fdc
	else
Packit 549fdc
		ret = 0;	/* timeout */
Packit 549fdc
Packit 549fdc
#ifdef EAGAIN_DEBUG
Packit 549fdc
	fprintf(stderr,
Packit 549fdc
		"eagain: server_pull_timeout: %d (avail: cli %d, serv %d)\n",
Packit 549fdc
		ret, (int) to_client_len, (int) to_server_len);
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
	return ret;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
inline static int client_pull_timeout_func(gnutls_transport_ptr_t ptr,
Packit 549fdc
					   unsigned int ms)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
Packit 549fdc
	if (to_client_len > 0)
Packit 549fdc
		ret = 1;
Packit 549fdc
	else
Packit 549fdc
		ret = 0;
Packit 549fdc
Packit 549fdc
#ifdef EAGAIN_DEBUG
Packit 549fdc
	fprintf(stderr,
Packit 549fdc
		"eagain: client_pull_timeout: %d (avail: cli %d, serv %d)\n",
Packit 549fdc
		ret, (int) to_client_len, (int) to_server_len);
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
	return ret;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
inline static void reset_buffers(void)
Packit 549fdc
{
Packit 549fdc
	to_server_len = 0;
Packit 549fdc
	to_client_len = 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
inline static int record_send_loop(gnutls_session_t session,
Packit 549fdc
				   const void *data, size_t sizeofdata,
Packit 549fdc
				   int use_null_on_retry)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
	const void *retry_data;
Packit 549fdc
	size_t retry_sizeofdata;
Packit 549fdc
Packit 549fdc
	if (use_null_on_retry) {
Packit 549fdc
		retry_data = 0;
Packit 549fdc
		retry_sizeofdata = 0;
Packit 549fdc
	} else {
Packit 549fdc
		retry_data = data;
Packit 549fdc
		retry_sizeofdata = sizeofdata;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	ret = gnutls_record_send(session, data, sizeofdata);
Packit 549fdc
	while (ret == GNUTLS_E_AGAIN) {
Packit 549fdc
		ret =
Packit 549fdc
		    gnutls_record_send(session, retry_data,
Packit 549fdc
					retry_sizeofdata);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	return ret;
Packit 549fdc
}