Hi Robin,
             I am using DTLSv1_listen() and calling it repeatedly the
difference (I believe)  is I am using non-blocking sockets. Please
find attached the sample program from sctp.fh-muenster.de modified for
non-blocking sockets using select that demonstrates this problem.

You can compile the program using:

gcc dtls_udp_echo.c -o server -I openssl-1.0.0d/include -l pthread -l
dl openssl-1.0.0d/libssl.a  openssl-1.0.0d//libcrypto.a

and to run this use instructions below:

On the server:

./server -s -L 10.10.100.116 -p 6666 -V

On the client

./server -r 10.10.100.116 -L 0.0.0.0 -p 6666 -v -l 1400 -n 10


Thanks,
-Yogi



On Sat, Jul 2, 2011 at 2:05 AM, Robin Seggelmann
<seggelm...@fh-muenster.de> wrote:
> Hi Yogesh,
>
> On 01.07.2011, at 00:59, Yogesh Chopra wrote:
>
>> The setup is same as before (where traffic from server is blocked to
>> client). The Server responds only once with a HELLO_VERIFY response
>> for a HELLO request and then never sends a HELLO_VERIFY response for
>> subsequent CLIENT HELLO messages
>>
>> CLIENT                                      SERVER
>> HELLO --->
>>                                                 HELLO_VERIFY  (For
>> First request)
>>
>> Post first request
>>
>> HELLO --->
>>                                                There is no response from 
>> SERVER
>
> I tried to reproduce this behavior, but my DTLS programs (available on 
> sctp.fh-muenster.de) behave as expected. The server responds to every 
> ClientHello with a HelloVerifyRequest, which will be dropped due to a 
> firewall policy. The client keeps repeating until I remove the fw policy, 
> after which the handshake will be completed immediately.
>
> It is possible that your application does not handle this correctly? Are you 
> using DTLSv1_listen() and call it again and again until it returns 1? That 
> may not be the case, because the second ClientHello as a response to a 
> HelloVerifyRequest is necessary for this call to return successfully, before 
> you can create a new socket for the new connection and complete the handshake 
> for it. Please have a look at the programs on our website.
>
> Maybe you can provide an excerpt of your code which handles incoming 
> connections.
>
> Best regards
> Robin
>
>
>
>
>
> ______________________________________________________________________
> OpenSSL Project                                 http://www.openssl.org
> Development Mailing List                       openssl-dev@openssl.org
> Automated List Manager                           majord...@openssl.org
>
/*
 * Copyright (C) 2009 Robin Seggelmann, seggelm...@fh-muenster.de,
 *                    Michael Tuexen, tue...@fh-muenster.de
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <sys/select.h>
#include <fcntl.h>

#ifdef __linux__
#include <getopt.h>
#endif
#ifdef OPENSSL_FIPS
#include <openssl/fips.h>
#endif

#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>



#define BUFFER_SIZE          (1<<16)
#define COOKIE_SECRET_LENGTH 16

int verbose = 0;
int veryverbose = 0;
unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
int cookie_initialized=0;

char Usage[] =
"Usage: dtls_udp_echo [options] [address]\n"
"Options:\n"
"        -l      message length (Default: 100 Bytes)\n"
"        -p      port (Default: 23232)\n"
"        -n      number of messages to send (Default: 5)\n"
"        -v      verbose\n"
"        -V      very verbose\n";

static pthread_mutex_t* mutex_buf = NULL;

static void locking_function(int mode, int n, const char *file, int line) {
	if (mode & CRYPTO_LOCK)
		pthread_mutex_lock(&mutex_buf[n]);
	else
		pthread_mutex_unlock(&mutex_buf[n]);
}

static unsigned long id_function() {
	return (unsigned long) pthread_self();
}

int set_non_blocking(int fd)
{
  int flags;
  int result;


  /* If they have O_NONBLOCK, use the Posix way to do it */
#if defined(O_NONBLOCK)
  /* Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */
  if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
    flags = 0;
  result = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#else
  /* Otherwise, use the old way of doing it */
  flags = 1;
  result = ioctl(fd, FIOBIO, &flags);
  
#endif

  if (result != 0)
    {

      printf("Failed to set tcp socket non-blocking\n");
      return (-1);
    }
  
  return (0);

}



int THREAD_setup() {
	int i;

	mutex_buf = (pthread_mutex_t*) malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
	if (!mutex_buf)
		return 0;
	for (i = 0; i < CRYPTO_num_locks(); i++)
		pthread_mutex_init(&mutex_buf[i], NULL);
	CRYPTO_set_id_callback(id_function);
	CRYPTO_set_locking_callback(locking_function);
	return 1;
}

int THREAD_cleanup() {
	int i;

	if (!mutex_buf)
		return 0;

	CRYPTO_set_id_callback(NULL);
	CRYPTO_set_locking_callback(NULL);
	for (i = 0; i < CRYPTO_num_locks(); i++)
		pthread_mutex_destroy(&mutex_buf[i]);
	free(mutex_buf);
	mutex_buf = NULL;
	return 1;
}

int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
	{
	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
	unsigned int length = 0, resultlength;
	union {
		struct sockaddr_storage ss;
		struct sockaddr_in6 s6;
		struct sockaddr_in s4;
	} peer;

	/* Initialize a random secret */
	if (!cookie_initialized)
		{
		if (!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH))
			{
			printf("error setting random cookie secret\n");
			return 0;
			}
		cookie_initialized = 1;
		}

	/* Read peer information */
	(void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

	/* Create buffer with peer's address and port */
	length = 0;
	switch (peer.ss.ss_family) {
		case AF_INET:
			length += sizeof(struct in_addr);
			break;
		case AF_INET6:
			length += sizeof(struct in6_addr);
			break;
		default:
			OPENSSL_assert(0);
			break;
	}
	length += sizeof(in_port_t);
	buffer = (unsigned char*) OPENSSL_malloc(length);

	if (buffer == NULL)
		{
		printf("out of memory\n");
		return 0;
		}

	switch (peer.ss.ss_family) {
		case AF_INET:
			memcpy(buffer,
			       &peer.s4.sin_port,
			       sizeof(in_port_t));
			memcpy(buffer + sizeof(peer.s4.sin_port),
			       &peer.s4.sin_addr,
			       sizeof(struct in_addr));
			break;
		case AF_INET6:
			memcpy(buffer,
			       &peer.s6.sin6_port,
			       sizeof(in_port_t));
			memcpy(buffer + sizeof(in_port_t),
			       &peer.s6.sin6_addr,
			       sizeof(struct in6_addr));
			break;
		default:
			OPENSSL_assert(0);
			break;
	}

	/* Calculate HMAC of buffer using the secret */
	HMAC(EVP_sha1(), (const void*) cookie_secret, COOKIE_SECRET_LENGTH,
	     (const unsigned char*) buffer, length, result, &resultlength);
	OPENSSL_free(buffer);
	memcpy(cookie, result, resultlength);
	*cookie_len = resultlength;

	return 1;
}

int verify_cookie(SSL *ssl, unsigned char *cookie, unsigned int cookie_len)
	{
	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
	unsigned int length = 0, resultlength;
	union {
		struct sockaddr_storage ss;
		struct sockaddr_in6 s6;
		struct sockaddr_in s4;
	} peer;

	/* If secret isn't initialized yet, the cookie can't be valid */
	if (!cookie_initialized)
		return 0;

	/* Read peer information */
	(void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);

	/* Create buffer with peer's address and port */
	length = 0;
	switch (peer.ss.ss_family) {
		case AF_INET:
			length += sizeof(struct in_addr);
			break;
		case AF_INET6:
			length += sizeof(struct in6_addr);
			break;
		default:
			OPENSSL_assert(0);
			break;
	}
	length += sizeof(in_port_t);
	buffer = (unsigned char*) OPENSSL_malloc(length);

	if (buffer == NULL)
		{
		printf("out of memory\n");
		return 0;
		}

	switch (peer.ss.ss_family) {
		case AF_INET:
			memcpy(buffer,
			       &peer.s4.sin_port,
			       sizeof(in_port_t));
			memcpy(buffer + sizeof(in_port_t),
			       &peer.s4.sin_addr,
			       sizeof(struct in_addr));
			break;
		case AF_INET6:
			memcpy(buffer,
			       &peer.s6.sin6_port,
			       sizeof(in_port_t));
			memcpy(buffer + sizeof(in_port_t),
			       &peer.s6.sin6_addr,
			       sizeof(struct in6_addr));
			break;
		default:
			OPENSSL_assert(0);
			break;
	}

	/* Calculate HMAC of buffer using the secret */
	HMAC(EVP_sha1(), (const void*) cookie_secret, COOKIE_SECRET_LENGTH,
	     (const unsigned char*) buffer, length, result, &resultlength);
	OPENSSL_free(buffer);

	if (cookie_len == resultlength && memcmp(result, cookie, resultlength) == 0)
		return 1;

	return 0;
	}

struct pass_info {
	union {
		struct sockaddr_storage ss;
		struct sockaddr_in6 s6;
		struct sockaddr_in s4;
	} server_addr, client_addr;
	SSL *ssl;
};

int dtls_verify_callback (int ok, X509_STORE_CTX *ctx) {
	/* This function should ask the user
	 * if he trusts the received certificate.
	 * Here we always trust.
	 */
	return 1;
}

void* connection_handle(void *info) {
  ssize_t len;
	char buf[BUFFER_SIZE];
	char addrbuf[INET6_ADDRSTRLEN];
	struct pass_info *pinfo = (struct pass_info*) info;
	SSL *ssl = pinfo->ssl;
	int fd, reading = 0, ret;
	const int on = 1;
        int count = 0;
	fd_set rfds;
	struct timeval tv;
	int retval;
        int accept = 0;

	pthread_detach(pthread_self());

	OPENSSL_assert(pinfo->client_addr.ss.ss_family == pinfo->server_addr.ss.ss_family);
	fd = socket(pinfo->client_addr.ss.ss_family, SOCK_DGRAM, 0);
	if (fd < 0) {
		perror("socket");
		goto cleanup;
	}

          	set_non_blocking(fd);
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on, (socklen_t) sizeof(on));
#ifdef SO_REUSEPORT
	setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &on, (socklen_t) sizeof(on));
#endif
	switch (pinfo->client_addr.ss.ss_family) {
		case AF_INET:
			bind(fd, (const struct sockaddr *) &pinfo->server_addr, sizeof(struct sockaddr_in));
			connect(fd, (struct sockaddr *) &pinfo->client_addr, sizeof(struct sockaddr_in));
			break;
		case AF_INET6:
			bind(fd, (const struct sockaddr *) &pinfo->server_addr, sizeof(struct sockaddr_in6));
			connect(fd, (struct sockaddr *) &pinfo->client_addr, sizeof(struct sockaddr_in6));
			break;
		default:
			OPENSSL_assert(0);
			break;
	}

	/* Set new fd and set BIO to connected */
	BIO_set_fd(SSL_get_rbio(ssl), fd, BIO_NOCLOSE);
	BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_CONNECTED, 0, &pinfo->client_addr.ss);

	if (SSL_accept(ssl) < 0)
	{    
	  perror("SSL_accept");
	  printf("%s\n", ERR_error_string(ERR_get_error(), buf));	  
	}
        else
	  {
            accept = 1;
	    printf("SSL accept successul first time\n");
	  }

	while(!accept)
	  {

	    while (1)
	      {

		/* Watch stdin (fd 0) to see when it has input. */
		FD_ZERO(&rfds);
		FD_SET(fd, &rfds);
		
		/* Wait up to five seconds. */
		tv.tv_sec = 10;
		tv.tv_usec = 0;
		
		retval = select(fd+1, &rfds, NULL, NULL, &tv);
		  /* Don't rely on the value of tv now! */
		
		if (retval == -1)
		  perror("C...select()");
		else if (retval)
		  {
		    printf("C  data is available now.\n");
		    break;
		  }
		/* FD_ISSET(0, &rfds) will be true. */
		else
		  printf("C...No data within five seconds.\n");
	      }

	/* Finish handshake */
	    ret = SSL_accept(ssl); 
	    
	    if (ret == 0)
	      {
		printf("SSL accept error \n");
		printf("%s\n", ERR_error_string(ERR_get_error(), buf));
		goto cleanup;
	      }
	    
	    if (ret < 0) {
	      perror("SSL_accept");
	      printf("%s\n", ERR_error_string(ERR_get_error(), buf));
              continue;
	    }

	    break;

	  }

	if (verbose) {
		if (pinfo->client_addr.ss.ss_family == AF_INET) {
			printf ("\nThread %lx: accepted connection from %s:%d\n",
			        (long) pthread_self(),
			        inet_ntop(AF_INET, &pinfo->client_addr.s4.sin_addr, addrbuf, INET6_ADDRSTRLEN),
			        ntohs(pinfo->client_addr.s4.sin_port));
		} else {
			printf ("\nThread %lx: accepted connection from %s:%d\n",
			        (long) pthread_self(),
			        inet_ntop(AF_INET6, &pinfo->client_addr.s6.sin6_addr, addrbuf, INET6_ADDRSTRLEN),
			        ntohs(pinfo->client_addr.s6.sin6_port));
		}
	}

	if (veryverbose) {
		printf ("------------------------------------------------------------\n");
		X509_NAME_print_ex_fp(stdout, X509_get_subject_name(SSL_get_peer_certificate(ssl)),
							  1, XN_FLAG_MULTILINE);
		printf("\n\n Cipher: %s", SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
		printf ("\n------------------------------------------------------------\n\n");
	}


	while (1)
	  {

	    int shutdown = 0;
	    while (1)
	      {
		
		/* Watch stdin (fd 0) to see when it has input. */
		FD_ZERO(&rfds);
		FD_SET(fd, &rfds);
		
		/* Wait up to five seconds. */
		tv.tv_sec = 5;
		tv.tv_usec= 0;
		
		retval = select(fd+1, &rfds, NULL, NULL, &tv);
		/* Don't rely on the value of tv now! */
		
		if (retval == -1)
		  perror("D...select()");
		else if (retval)
		  {
		    printf("Thread %lx: Data available: %d\n", (long) pthread_self(), fd);
		    break;
		  }
		/* FD_ISSET(0, &rfds) will be true. */
		else
                {
		  printf("Thread %lx: Time out.....: %d\n", (long) pthread_self(), fd);
                }
	      }
	    
	    
	    len = SSL_read(ssl, buf, sizeof(buf));
	    
	    switch (SSL_get_error(ssl, len)) 
	      {
	      case SSL_ERROR_NONE:
		if (verbose) {
		  printf("Thread %lx: read %d bytes message: %d\n", (long) pthread_self(), (int) len, count++);
		}
		reading = 0;
		break;
	      case SSL_ERROR_WANT_READ:
		printf("ERROR_WANT_READ.. try again\n");
		/* Just try again */
		break;
	      case SSL_ERROR_ZERO_RETURN:
		printf("ERROR_ZERO_RETURN.. try again\n");
		reading = 0;
		/* SSL shutdown */
		if ((SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN)) 
		  {
		    printf("Thread %lx: SHUTDOWN RECEIVED.: \n", (long) pthread_self());
		    shutdown = 1;
		  }  
		else
		  printf("Thread %lx: SHUTDOWN NOT ....RECEIVED.: \n", (long) pthread_self());
		break;
		
	      default:
		    printf("Unexpected error while reading: %d\n", SSL_get_error(ssl, len));
		    printf("%s\n", ERR_error_string(ERR_get_error(), buf));
		    goto cleanup;
		    break;
	      }
		
	    if (shutdown)
	      break;
	    
	  }
	    SSL_shutdown(ssl);

cleanup:
	close(fd);
	free(info);
	SSL_free(ssl);
	ERR_remove_state(0);
	if (verbose)
		printf("Thread %lx: done, connection closed.\n", (long) pthread_self());
	pthread_exit( (void *) NULL );
}


void start_server(int port, char *local_address) {
	int fd;
	union {
		struct sockaddr_storage ss;
		struct sockaddr_in s4;
		struct sockaddr_in6 s6;
	} server_addr, client_addr;
	pthread_t tid;
	SSL_CTX *ctx;
	SSL *ssl;
	BIO *bio;
	struct timeval timeout;
	struct pass_info *info;
	const int on = 1;
	fd_set rfds;
	struct timeval tv;
	int retval;

	memset(&server_addr, 0, sizeof(struct sockaddr_storage));
	if (strlen(local_address) == 0) {
		server_addr.s6.sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
		server_addr.s6.sin6_len = sizeof(struct sockaddr_in6);
#endif
		server_addr.s6.sin6_addr = in6addr_any;
		server_addr.s6.sin6_port = htons(port);
	} else {
		if (inet_pton(AF_INET, local_address, &server_addr.s4.sin_addr) == 1) {
			server_addr.s4.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
			server_addr.s4.sin_len = sizeof(struct sockaddr_in);
#endif
			server_addr.s4.sin_port = htons(port);
		} else if (inet_pton(AF_INET6, local_address, &server_addr.s6.sin6_addr) == 1) {
			server_addr.s6.sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
			server_addr.s6.sin6_len = sizeof(struct sockaddr_in6);
#endif
			server_addr.s6.sin6_port = htons(port);
		} else {
			return;
		}
	}

	THREAD_setup();

#ifdef OPENSSL_FIPS
     if (!FIPS_mode_set(1))
     {
       ERR_load_crypto_strings();
       ERR_print_errors_fp(stderr);
       exit(1);
     }
 
     printf("FIPS enabled\n");
#endif



	OpenSSL_add_ssl_algorithms();
	SSL_load_error_strings();
	ctx = SSL_CTX_new(DTLSv1_server_method());
	/* We accept all ciphers, including NULL.
	 * Not recommended beyond testing and debugging
	 */
	//SSL_CTX_set_cipher_list(ctx, "ALL:NULL:eNULL:aNULL");
	SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);

	if (!SSL_CTX_use_certificate_file(ctx, "server-cert.pem", SSL_FILETYPE_PEM))
		printf("\nERROR: no certificate found!");

	if (!SSL_CTX_use_PrivateKey_file(ctx, "server-key.pem", SSL_FILETYPE_PEM))
		printf("\nERROR: no private key found!");

	if (!SSL_CTX_check_private_key (ctx))
		printf("\nERROR: invalid private key!");

	/* Client has to authenticate */
	SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, dtls_verify_callback);
	
        SSL_CTX_set_read_ahead(ctx, 1);
	SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);
	SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie);

	fd = socket(server_addr.ss.ss_family, SOCK_DGRAM, 0);
	if (fd < 0) {
		perror("socket");
		exit(-1);
	}

	set_non_blocking(fd);
        
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on, (socklen_t) sizeof(on));
#ifdef SO_REUSEPORT
	setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &on, (socklen_t) sizeof(on));
#endif
	if (server_addr.ss.ss_family == AF_INET) {
		bind(fd, (const struct sockaddr *) &server_addr, sizeof(struct sockaddr_in));
	} else {
		bind(fd, (const struct sockaddr *) &server_addr, sizeof(struct sockaddr_in6));
	}


 	

	memset(&client_addr, 0, sizeof(struct sockaddr_storage));
	
	/* Create BIO */
	bio = BIO_new_dgram(fd, BIO_NOCLOSE);
	
	ssl = SSL_new(ctx);
	
	SSL_set_bio(ssl, bio, bio);
	SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
	

	while (1) {
	  int ret;

		while (1)
		{

		  /* Watch stdin (fd 0) to see when it has input. */
		  FD_ZERO(&rfds);
		  FD_SET(fd, &rfds);
		  
		  /* Wait up to five seconds. */
		  tv.tv_sec = 5;
		  tv.tv_usec = 0;
		  

		  retval = select(fd+1, &rfds, NULL, NULL, &tv);
		  /* Don't rely on the value of tv now! */

		  if (retval == -1)
		    perror("select()");
		  else if (retval)
		  {
		    printf("Listen thread Data is available now.\n");
		    break;
		  }
		  /* FD_ISSET(0, &rfds) will be true. */
		  else
		    printf("Listen thread No data within five seconds.\n");
		}

		if ((ret = DTLSv1_listen(ssl, &client_addr)) < 0)
		  {
                    printf("Listen thread 1In progress Listen ret code = %d\n", ret);
		  }
		else if (ret == 0)
		{
                    printf("Listen thread Error Listen ret code = %d\n", ret);
		} 
                else if (ret == 1)
		{
		  
		  info = (struct pass_info*) malloc (sizeof(struct pass_info));
		  memcpy(&info->server_addr, &server_addr, sizeof(struct sockaddr_storage));
		  memcpy(&info->client_addr, &client_addr, sizeof(struct sockaddr_storage));
		  info->ssl = ssl;
		  memset(&client_addr, 0, sizeof(struct sockaddr_storage));
		  
		  /* Create BIO */
		  bio = BIO_new_dgram(fd, BIO_NOCLOSE);
		  
		  ssl = SSL_new(ctx);
		  
		  SSL_set_bio(ssl, bio, bio);
		  SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);

		  if (pthread_create( &tid, NULL, connection_handle, info) != 0) {
		   perror("pthread_create");
		   exit(-1);
		  }
		  
		  //sleep(1000);
 
		}
                else
                    printf("unhandled Error Listen ret code = %d\n", ret);
	}

	THREAD_cleanup();
}

void start_client(char *remote_address, char *local_address, int port, int length, int messagenumber) {
	int fd;
	union {
                struct sockaddr_storage ss;
		struct sockaddr_in s4;
		struct sockaddr_in6 s6;
	} remote_addr, local_addr;
	char buf[BUFFER_SIZE];
	char addrbuf[INET6_ADDRSTRLEN];
	socklen_t len;
	SSL_CTX *ctx;
	SSL *ssl;
	BIO *bio;
	int reading = 0;
	struct timeval timeout;
	fd_set rfds, wfds;
	struct timeval tv;
	int retval;
	int flag = 1;
 

        memset(buf, 'a', sizeof(buf));
	memset((void *) &remote_addr, 0, sizeof(struct sockaddr_storage));
	memset((void *) &local_addr, 0, sizeof(struct sockaddr_storage));

	if (inet_pton(AF_INET, remote_address, &remote_addr.s4.sin_addr) == 1) {
		remote_addr.s4.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
		remote_addr.s4.sin_len = sizeof(struct sockaddr_in);
#endif
		remote_addr.s4.sin_port = htons(port);
	} else if (inet_pton(AF_INET6, remote_address, &remote_addr.s6.sin6_addr) == 1) {
		remote_addr.s6.sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
		remote_addr.s6.sin6_len = sizeof(struct sockaddr_in6);
#endif
		remote_addr.s6.sin6_port = htons(port);
	} else {
		return;
	}

	fd = socket(remote_addr.ss.ss_family, SOCK_DGRAM, 0);
	if (fd < 0) {
		perror("socket");
		exit(-1);
	}
	
        set_non_blocking(fd);

	if (strlen(local_address) > 0) {
		if (inet_pton(AF_INET, local_address, &local_addr.s4.sin_addr) == 1) {
			local_addr.s4.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
			local_addr.s4.sin_len = sizeof(struct sockaddr_in);
#endif
			local_addr.s4.sin_port = htons(0);
		} else if (inet_pton(AF_INET6, local_address, &local_addr.s6.sin6_addr) == 1) {
			local_addr.s6.sin6_family = AF_INET6;
#ifdef HAVE_SIN6_LEN
			local_addr.s6.sin6_len = sizeof(struct sockaddr_in6);
#endif
			local_addr.s6.sin6_port = htons(0);
		} else {
			return;
		}
		OPENSSL_assert(remote_addr.ss.ss_family == local_addr.ss.ss_family);
		if (local_addr.ss.ss_family == AF_INET) {
			bind(fd, (const struct sockaddr *) &local_addr, sizeof(struct sockaddr_in));
		} else {
			bind(fd, (const struct sockaddr *) &local_addr, sizeof(struct sockaddr_in6));
		}
	}


#ifdef OPENSSL_FIPS
     if (!FIPS_mode_set(1))
     {  
       ERR_load_crypto_strings();
       ERR_print_errors_fp(stderr);
       exit(1);
     }  

     printf("FIPS enabled\n");
#endif
	OpenSSL_add_ssl_algorithms();
	SSL_load_error_strings();
	ctx = SSL_CTX_new(DTLSv1_client_method());
	//SSL_CTX_set_cipher_list(ctx, "eNULL:!MD5");

	if (!SSL_CTX_use_certificate_file(ctx, "client-cert.pem", SSL_FILETYPE_PEM))
		printf("\nERROR: no certificate found!");

	if (!SSL_CTX_use_PrivateKey_file(ctx, "client-key.pem", SSL_FILETYPE_PEM))
		printf("\nERROR: no private key found!");

	if (!SSL_CTX_check_private_key (ctx))
		printf("\nERROR: invalid private key!");

	//SSL_CTX_set_verify_depth (ctx, 2);
	SSL_CTX_set_read_ahead(ctx, 1);


	if (remote_addr.ss.ss_family == AF_INET) {
		connect(fd, (struct sockaddr *) &remote_addr, sizeof(struct sockaddr_in));
	} else {
		connect(fd, (struct sockaddr *) &remote_addr, sizeof(struct sockaddr_in6));
	}

	ssl = SSL_new(ctx);

	/* Create BIO, connect and set to already connected */
	bio = BIO_new_dgram(fd, BIO_CLOSE);
	BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &remote_addr.ss);

	/* Set and activate timeouts */
	//timeout.tv_sec = 2;
	//timeout.tv_usec = 0;
	SSL_set_bio(ssl, bio, bio);

	//BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);

	printf("Start SSL_connect\n");

	 while (1)
	   {
	     
	     int success = 0;
	     /* Watch stdin (fd 0) to see when it has input. */
	     FD_ZERO(&rfds);
	     FD_SET(fd, &rfds);
	     
	     /* Wait up to five seconds. */
	     tv.tv_sec = 10;
	     tv.tv_usec = 0;

	     
	     if (flag == 1)
	     {
	       flag = 0;
	       if (SSL_connect(ssl) < 0)      
	       {
		 perror("SSL_connect");
		 printf("%s \n", ERR_error_string(ERR_get_error(), buf));
	       }
               else
	       {
		 printf ("SSL_connect successful first time....\n");
		 break;
	       }
	     }	     

	     /* handle timeout */

	     DTLSv1_handle_timeout(ssl);

	     retval = select(fd+1, &rfds, NULL, NULL, &tv);
	     /* Don't rely on the value of tv now! */

	     if (retval == -1)
	       perror("CC...select()");
	     else if (retval)
	       {
		 int retcode;
		 printf("CC  data is available now.\n");
		 printf("CC  SSL_connect .\n");
		 retcode = SSL_connect(ssl);
		 switch (SSL_get_error(ssl, retcode))
		 {

		 case SSL_ERROR_NONE:
		   printf("SSL connect successful\n");
		   success = 1;
		   break;

		 case SSL_ERROR_WANT_READ:
		   printf("ERROR_WANT_READ.. try again\n");
		   /* Just try again */
		   break;
		 case SSL_ERROR_ZERO_RETURN:
		   printf("ERROR_ZERO_RETURN.. try again\n");
		   break;
		   
		 default:
		   printf("Unexpected error while connect: %d\n", SSL_get_error(ssl, len));
		   printf("%s\n", ERR_error_string(ERR_get_error(), buf));
		   goto cleanup;
		   break;
		 }

		 if(success)
                   break;
 
		 
	       }
	     /* FD_ISSET(0, &rfds) will be true. */
	     else
	       printf("CC...No data within five seconds.\n");
	   }
	 
 
	if (verbose) {
		if (remote_addr.ss.ss_family == AF_INET) {
			printf ("\nConnected to %s\n",
			         inet_ntop(AF_INET, &remote_addr.s4.sin_addr, addrbuf, INET6_ADDRSTRLEN));
		} else {
			printf ("\nConnected to %s\n",
			         inet_ntop(AF_INET6, &remote_addr.s6.sin6_addr, addrbuf, INET6_ADDRSTRLEN));
		}
	}

	if (veryverbose) {
		printf ("------------------------------------------------------------\n");
		X509_NAME_print_ex_fp(stdout, X509_get_subject_name(SSL_get_peer_certificate(ssl)),
		                      1, XN_FLAG_MULTILINE);
		printf("\n\n Cipher: %s", SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)));
		printf ("\n------------------------------------------------------------\n\n");
	}

	while (messagenumber > 0) 
	  { 


	    int shutdown = 0;
	    while (1)
	      {
		
		/* Watch stdin (fd 0) to see when it has input. */
		FD_ZERO(&wfds);
		FD_SET(fd, &wfds);
		
		/* Wait up to five seconds. */
		tv.tv_sec = 5;
		tv.tv_usec= 0;
		
		retval = select(fd+1, &rfds, &wfds, NULL, &tv);
		/* Don't rely on the value of tv now! */
		
		if (retval == -1)
		  perror("DD...select()");
		else if (retval)
		{
		  if (FD_ISSET(fd, &wfds))
		  {
		    printf("Thread %lx: fd ready to write: %d\n", (long) pthread_self(), fd);

		    len = SSL_write(ssl, buf, length);
		    break;
		  }
		  else if (FD_ISSET(fd, &rfds)) 
		  {
		    /* SSL shutdown */
		    if ((SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN)) 
		    {
		      printf("Thread %lx: SHUTDOWN RECEIVED.: \n", (long) pthread_self());
		      shutdown = 1;
		    }  
		    else
		      printf("Thread %lx: SHUTDOWN NOT ....RECEIVED.: \n", (long) pthread_self());
		  }

		}
		else
                {
		  printf("Thread %lx: Time out.....: %d\n", (long) pthread_self(), fd);
                }
	      }

	    if (shutdown)
	    {
	      SSL_shutdown(ssl);
              break;
	    }
	    
	    switch (SSL_get_error(ssl, len)) 
	      {
	      case SSL_ERROR_NONE:
		if (verbose) {
		  printf("wrote %d bytes message: %d\n", (int) len, messagenumber);
		}
		messagenumber--;
		break;
	      case SSL_ERROR_WANT_WRITE:
		/* Just try again later */
		break;
	      case SSL_ERROR_WANT_READ:
		/* continue with reading */
		break;
	      default:
		printf("Unexpected error while writing: %d\n", SSL_get_error(ssl, len));
		printf("%s\n", ERR_error_string(ERR_get_error(), buf));
		exit(1);
		break;
	      }
	    
	    if (messagenumber == 2)
	      {
		printf("sending DTLSv1 heartbeat\n");
		DTLSv1_send_heartbeat(ssl);
	      }
	    if (messagenumber == 0)
	      {
		printf("sending DTLSv1 Shutdown\n");
		SSL_shutdown(ssl);
		break;
	      }

	  }

 cleanup: close(fd);
	if (verbose)
	  printf("Connection closed.\n");
	
}

int main(int argc, char **argv)
{
	int port = 23232;
	int length = 100;
	int messagenumber = 5;
	char local_addr[INET6_ADDRSTRLEN+1];
	char remote_addr[INET6_ADDRSTRLEN+1];
	char c;
        int server = 0;

	memset(local_addr, 0, INET6_ADDRSTRLEN+1);

	while ((c = getopt(argc, argv, "p:l:n:L:vVr:s")) != -1)
		switch(c) {
			case 'l':
				length = atoi(optarg);
				if (length > BUFFER_SIZE)
					length = BUFFER_SIZE;
				break;
			case 'n':
				messagenumber = atoi(optarg);
				break;
			case 'p':
				port = atoi(optarg);
				break;
			case 'L':
				strncpy(local_addr, optarg, INET6_ADDRSTRLEN);
				break;
			case 'v':
				verbose = 1;
				break;
			case 'V':
				verbose = 1;
				veryverbose = 1;
				break;
                        case 's' :
                                server = 1;
                                break;
                        case 'r' :
				strncpy(remote_addr, optarg, INET6_ADDRSTRLEN);
                                break;
			default:
				fprintf(stderr, "%s\n", Usage);
				exit(1);
		}
	
	if (server)
		start_server(port, local_addr);
	else
		start_client(remote_addr, local_addr, port, length, messagenumber);

	return 0;
}

Reply via email to