#include <stdio.h>
#include <errno.h>
#include <openssl/ssl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


/*
 * Create an SSL object with two different datagram BIOs for read and write.
 * The write BIO will send UDP packets to the server, but the server's
 * response won't be read. This simulates losing the HelloVerifyRequest
 * packet from the server.
 *
 * No one said this code is written well.  It's just throwaway code meant
 * to test a very specific situation, so we skip all kinds of error checking.
 */

int main (int argc, char * argv [])
{
    struct sockaddr_in destaddr, dummyaddr;
    SSL_CTX * ctx;
    SSL * ssl;
    BIO * rbio, * wbio;
    int s, s2;
    char buf [4096];

    if (argc != 3)
    {
        fprintf (stderr, "Usage: %s destIP destPort\n", argv [0]);
        return 1;
    }

    destaddr.sin_family = AF_INET;
    destaddr.sin_addr.s_addr = inet_addr (argv [1]);
    destaddr.sin_port = htons (atoi (argv [2]));

    SSL_library_init ();
    SSL_load_error_strings ();

    ctx = SSL_CTX_new (DTLSv1_method ());
    SSL_CTX_set_cipher_list (ctx, "HIGH");
    SSL_CTX_set_read_ahead (ctx, 1);

    s = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (s == -1)
    {
        perror ("socket");
        return 1;
    }
    
    s2 = socket (AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
    if (s == -1)
    {
        perror ("socket");
        return 1;
    }

    wbio = BIO_new_dgram (s, BIO_CLOSE);
    BIO_dgram_set_peer (wbio, & destaddr);

    dummyaddr.sin_family = AF_INET;
    dummyaddr.sin_addr.s_addr = htonl (INADDR_ANY);
    dummyaddr.sin_port = htons (4321); /* any port unlikely to be in use */
    if (bind (s2, (struct sockaddr *) & dummyaddr, sizeof dummyaddr) == -1)
    {
        perror ("bind");
        return 1;
    }

    rbio = BIO_new_dgram (s2, BIO_CLOSE);
    BIO_dgram_set_peer (rbio, & destaddr);

    ssl = SSL_new (ctx);
    SSL_set_bio (ssl, rbio, wbio);
    ERR_clear_error ();

    if ((SSL_connect (ssl) == -1) &&
        (SSL_get_error (ssl, -1) == SSL_ERROR_WANT_READ))
    {
        puts ("Press ENTER ...");
        getchar ();
        recvfrom (s, buf, sizeof buf, 0, NULL, 0);
    }

    SSL_set_bio (ssl, wbio, wbio);

    SSL_connect (ssl);

    return 0;
}
