ssize_t socket_recv(const socket_st * socket, void *buffer, int buffer_size) { int ret; if (socket->secure) { do { ret = gnutls_record_recv(socket->session, buffer, buffer_size); if (ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED) gnutls_heartbeat_pong(socket->session, 0); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED); } else do { ret = recv(socket->fd, buffer, buffer_size, 0); } while (ret == -1 && errno == EINTR); return ret; }
static void client (int fd, int server_init) { gnutls_session_t session; int ret, ret2; char buffer[MAX_BUF + 1]; gnutls_anon_client_credentials_t anoncred; /* Need to enable anonymous KX specifically. */ gnutls_global_init (); if (debug) { gnutls_global_set_log_function (client_log_func); gnutls_global_set_log_level (4711); } gnutls_anon_allocate_client_credentials (&anoncred); /* Initialize TLS session */ gnutls_init (&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM); gnutls_heartbeat_enable (session, GNUTLS_HB_PEER_ALLOWED_TO_SEND); gnutls_dtls_set_mtu (session, 1500); /* Use default priorities */ gnutls_priority_set_direct (session, "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL", NULL); /* put the anonymous credentials to the current session */ gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred); gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) fd); /* Perform the TLS handshake */ do { ret = gnutls_handshake (session); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); if (ret < 0) { fail ("client: Handshake failed\n"); gnutls_perror (ret); exit (1); } else { if (debug) success ("client: Handshake was completed\n"); } if (debug) success ("client: DTLS version is: %s\n", gnutls_protocol_get_name (gnutls_protocol_get_version (session))); if (!server_init) { do { ret = gnutls_record_recv (session, buffer, sizeof (buffer)); if (ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED) { if (debug) success ("Ping received. Replying with pong.\n"); ret2 = gnutls_heartbeat_pong (session, 0); if (ret2 < 0) { fail ("pong: %s\n", gnutls_strerror (ret)); terminate (); } } } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED); } else { do { ret = gnutls_heartbeat_ping (session, 256, 5, GNUTLS_HEARTBEAT_WAIT); if (debug) success ("Ping sent.\n"); } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret < 0) { fail ("ping: %s\n", gnutls_strerror (ret)); terminate (); } } gnutls_bye (session, GNUTLS_SHUT_WR); close (fd); gnutls_deinit (session); gnutls_anon_free_client_credentials (anoncred); gnutls_global_deinit (); }
static void server (int fd, int server_init) { int ret, ret2; char buffer[MAX_BUF + 1]; gnutls_session_t session; gnutls_anon_server_credentials_t anoncred; /* this must be called once in the program */ gnutls_global_init (); if (debug) { gnutls_global_set_log_function (server_log_func); gnutls_global_set_log_level (4711); } gnutls_anon_allocate_server_credentials (&anoncred); session = initialize_tls_session (); gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred); gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) fd); do { ret = gnutls_handshake (session); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); if (ret < 0) { close (fd); gnutls_deinit (session); fail ("server: Handshake has failed (%s)\n\n", gnutls_strerror (ret)); terminate (); } if (debug) success ("server: Handshake was completed\n"); if (debug) success ("server: TLS version is: %s\n", gnutls_protocol_get_name (gnutls_protocol_get_version (session))); /* see the Getting peer's information example */ /* print_info(session); */ if (server_init) { do { ret = gnutls_record_recv (session, buffer, sizeof (buffer)); if (ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED) { if (debug) success ("Ping received. Replying with pong.\n"); ret2 = gnutls_heartbeat_pong (session, 0); if (ret2 < 0) { fail ("pong: %s\n", gnutls_strerror (ret)); terminate (); } } } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED); } else { do { ret = gnutls_heartbeat_ping (session, 256, 5, GNUTLS_HEARTBEAT_WAIT); if (debug) success ("Ping sent.\n"); } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret < 0) { fail ("ping: %s\n", gnutls_strerror (ret)); terminate (); } } /* do not wait for the peer to close the connection. */ gnutls_bye (session, GNUTLS_SHUT_WR); close (fd); gnutls_deinit (session); gnutls_anon_free_server_credentials (anoncred); gnutls_global_deinit (); if (debug) success ("server: finished\n"); }
void udp_server(const char *name, int port, int mtu) { int sock, ret; struct sockaddr_storage cli_addr; socklen_t cli_addr_size; char buffer[MAX_BUFFER]; priv_data_st priv; gnutls_session_t session; gnutls_datum_t cookie_key; gnutls_dtls_prestate_st prestate; unsigned char sequence[8]; ret = gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE); if (ret < 0) { fprintf(stderr, "Cannot generate key\n"); exit(1); } ret = listen_socket(name, port, SOCK_DGRAM); if (ret < 0) { fprintf(stderr, "Cannot listen\n"); exit(1); } for (;;) { printf("Waiting for connection...\n"); sock = wait_for_connection(); if (sock < 0) continue; cli_addr_size = sizeof(cli_addr); ret = recvfrom(sock, buffer, sizeof(buffer), MSG_PEEK, (struct sockaddr *) &cli_addr, &cli_addr_size); if (ret > 0) { memset(&prestate, 0, sizeof(prestate)); ret = gnutls_dtls_cookie_verify(&cookie_key, &cli_addr, cli_addr_size, buffer, ret, &prestate); if (ret < 0) { /* cookie not valid */ priv_data_st s; memset(&s, 0, sizeof(s)); s.fd = sock; s.cli_addr = (void *) &cli_addr; s.cli_addr_size = cli_addr_size; printf ("Sending hello verify request to %s\n", human_addr((struct sockaddr *) &cli_addr, cli_addr_size, buffer, sizeof(buffer))); gnutls_dtls_cookie_send(&cookie_key, &cli_addr, cli_addr_size, &prestate, (gnutls_transport_ptr_t) &s, push_func); /* discard peeked data */ recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) &cli_addr, &cli_addr_size); continue; } printf("Accepted connection from %s\n", human_addr((struct sockaddr *) &cli_addr, sizeof(cli_addr), buffer, sizeof(buffer))); } else continue; session = initialize_session(1); gnutls_dtls_prestate_set(session, &prestate); if (mtu) gnutls_dtls_set_mtu(session, mtu); priv.session = session; priv.fd = sock; priv.cli_addr = &cli_addr; priv.cli_addr_size = cli_addr_size; gnutls_transport_set_ptr(session, &priv); gnutls_transport_set_push_function(session, push_func); gnutls_transport_set_pull_function(session, pull_func); gnutls_transport_set_pull_timeout_function(session, pull_timeout_func); do { ret = gnutls_handshake(session); } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret < 0) { fprintf(stderr, "Error in handshake(): %s\n", gnutls_strerror(ret)); gnutls_deinit(session); continue; } for (;;) { do { ret = gnutls_record_recv_seq(session, buffer, MAX_BUFFER, sequence); if (ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED) gnutls_heartbeat_pong(session, 0); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED); if (ret == GNUTLS_E_REHANDSHAKE) { fprintf(stderr, "*** Received hello message\n"); do { ret = gnutls_handshake(session); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); if (ret == 0) continue; } if (ret < 0) { fprintf(stderr, "Error in recv(): %s\n", gnutls_strerror(ret)); break; } if (ret == 0) { printf("EOF\n\n"); break; } buffer[ret] = 0; printf ("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n", sequence[0], sequence[1], sequence[2], sequence[3], sequence[4], sequence[5], sequence[6], sequence[7], buffer); if (check_command(session, buffer) == 0) { /* reply back */ ret = gnutls_record_send(session, buffer, ret); if (ret < 0) { fprintf(stderr, "Error in send(): %s\n", gnutls_strerror(ret)); break; } } } } gnutls_deinit(session); }