gnutls-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gnutls branch, master, updated. gnutls_2_11_6-201-g089391d


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_2_11_6-201-g089391d
Date: Sat, 19 Feb 2011 18:08:46 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gnutls".

http://git.savannah.gnu.org/cgit/gnutls.git/commit/?id=089391da55d232908b9cdbba7f27b0ccfea26cca

The branch, master has been updated
       via  089391da55d232908b9cdbba7f27b0ccfea26cca (commit)
       via  b5c0c987913d93e0bb8414c4f48242ee8f350382 (commit)
       via  d4bc58b0999373f0659a3c6ac693539818db063c (commit)
      from  258d52ffb0112f457fa2503493b9f353d08bdf24 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 089391da55d232908b9cdbba7f27b0ccfea26cca
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Feb 19 16:57:44 2011 +0100

    Changes to allow DTLS server side to operate. Added a simple UDP server on 
gnutls-serv.
    Server other cleanups.

commit b5c0c987913d93e0bb8414c4f48242ee8f350382
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Feb 19 11:25:29 2011 +0100

    Allow setting the DTLS timeouts explicitly.

commit d4bc58b0999373f0659a3c6ac693539818db063c
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Feb 19 10:10:45 2011 +0100

    updated.

-----------------------------------------------------------------------

Summary of changes:
 doc/TODO                                  |    8 +-
 lib/Makefile.am                           |    2 +-
 lib/ext_session_ticket.c                  |    4 +-
 lib/gnutls_buffers.c                      |  152 ++--------------------
 lib/gnutls_buffers.h                      |    3 +-
 lib/gnutls_constate.c                     |   17 ++-
 lib/gnutls_dtls.c                         |  128 ++++++++++++++-----
 lib/gnutls_errors.c                       |    2 +
 lib/gnutls_handshake.c                    |   68 +++++-----
 lib/gnutls_int.h                          |   10 ++
 lib/gnutls_state.c                        |    5 +
 lib/{ext_srp.h => includes/gnutls/dtls.h} |   37 +++---
 lib/includes/gnutls/gnutls.h.in           |    8 +-
 lib/libgnutls.map                         |   10 +-
 lib/system.c                              |   25 +++-
 lib/system.h                              |    2 +-
 lib/system_override.c                     |  202 +++++++++++++++++++++++++++++
 src/Makefile.am                           |    2 +-
 src/cli.c                                 |    1 +
 src/serv-gaa.c                            |  117 +++++++++--------
 src/serv-gaa.h                            |   40 +++---
 src/serv.c                                |  122 +++++++++++++-----
 src/serv.gaa                              |    5 +-
 src/udp-serv.c                            |  174 +++++++++++++++++++++++++
 src/udp-serv.h                            |    8 +
 25 files changed, 807 insertions(+), 345 deletions(-)
 copy lib/{ext_srp.h => includes/gnutls/dtls.h} (58%)
 create mode 100644 lib/system_override.c
 create mode 100644 src/udp-serv.c
 create mode 100644 src/udp-serv.h

diff --git a/doc/TODO b/doc/TODO
index 811bd04..0be270d 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -3,7 +3,13 @@ anything), contact the developer's mailing list 
(address@hidden),
 in order to avoid having people working on the same thing. 
 
 Current list:
-+ Support PKCS#8 AES and DES-MD5 (tests/enc3pkcs8.pem) encrypted keys.
++ Allow setting a list of trusted plain certificates (not CAs) in the
+  gnutls_x509_trust_list_t, to verify against.
+* Allow setting a PKCS #11 module to gnutls_x509_trust_list_t, to verify 
+  against, similarly to NSS way.
+* Support replacing individual algorithms via a PKCS #11 module -
+  maybe use p11-kit for that.
+* Support PKCS#8 AES and DES-MD5 (tests/enc3pkcs8.pem) encrypted keys.
 * Implement Datagram-TLS (DTLS).
 * Implement TLS-PSK with PKCS #11.
 * Verify added CRLs (is it really needed?)
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 6a2b1dc..edf5209 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -81,7 +81,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c 
gnutls_cipher.c  \
        crypto.c random.c  ext_signature.c cryptodev.c system.c \
        crypto-api.c ext_safe_renegotiation.c gnutls_privkey.c \
        pkcs11.c pkcs11_privkey.c gnutls_pubkey.c pkcs11_write.c locks.c \
-       pkcs11_secret.c hash.c gnutls_dtls.c
+       pkcs11_secret.c hash.c gnutls_dtls.c system_override.c
 
 
 if ENABLE_NETTLE
diff --git a/lib/ext_session_ticket.c b/lib/ext_session_ticket.c
index 9c44b90..f51c127 100644
--- a/lib/ext_session_ticket.c
+++ b/lib/ext_session_ticket.c
@@ -683,10 +683,8 @@ _gnutls_send_new_session_ticket (gnutls_session_t session, 
int again)
 
       data_size = p - data;
     }
-  ret = _gnutls_send_handshake (session, data_size ? bufel : NULL,
+  return _gnutls_send_handshake (session, data_size ? bufel : NULL,
                                 GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
-
-  return ret;
 }
 
 int
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index a57784f..41b0244 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -68,58 +68,6 @@
  */
 #define MAX_QUEUE 16
 
-/**
- * gnutls_transport_set_errno:
- * @session: is a #gnutls_session_t structure.
- * @err: error value to store in session-specific errno variable.
- *
- * Store @err in the session-specific errno variable.  Useful values
- * for @err is EAGAIN and EINTR, other values are treated will be
- * treated as real errors in the push/pull function.
- *
- * This function is useful in replacement push/pull functions set by
- * gnutls_transport_set_push_function and
- * gnutls_transport_set_pullpush_function under Windows, where the
- * replacement push/pull may not have access to the same @errno
- * variable that is used by GnuTLS (e.g., the application is linked to
- * msvcr71.dll and gnutls is linked to msvcrt.dll).
- *
- * If you don't have the @session variable easily accessible from the
- * push/pull function, and don't worry about thread conflicts, you can
- * also use gnutls_transport_set_global_errno().
- **/
-void
-gnutls_transport_set_errno (gnutls_session_t session, int err)
-{
-  session->internals.errnum = err;
-}
-
-/**
- * gnutls_transport_set_global_errno:
- * @err: error value to store in global errno variable.
- *
- * Store @err in the global errno variable.  Useful values for @err is
- * EAGAIN and EINTR, other values are treated will be treated as real
- * errors in the push/pull function.
- *
- * This function is useful in replacement push/pull functions set by
- * gnutls_transport_set_push_function and
- * gnutls_transport_set_pullpush_function under Windows, where the
- * replacement push/pull may not have access to the same @errno
- * variable that is used by GnuTLS (e.g., the application is linked to
- * msvcr71.dll and gnutls is linked to msvcrt.dll).
- *
- * Whether this function is thread safe or not depends on whether the
- * global variable errno is thread safe, some system libraries make it
- * a thread-local variable.  When feasible, using the guaranteed
- * thread-safe gnutls_transport_set_errno() may be better.
- **/
-void
-gnutls_transport_set_global_errno (int err)
-{
-  errno = err;
-}
-
 /* Buffers received packets of type APPLICATION DATA and
  * HANDSHAKE DATA.
  */
@@ -451,16 +399,11 @@ _gnutls_writev_emu (gnutls_session_t session, const 
giovec_t * giovec,
 {
   int ret, j = 0;
   gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
-  void *iptr;
-  size_t sizeOfPtr;
   size_t total = 0;
 
   for (j = 0; j < giovec_cnt; j++)
     {
-      sizeOfPtr = giovec[j].iov_len;
-      iptr = giovec[j].iov_base;
-
-      ret = session->internals.push_func (fd, iptr, sizeOfPtr);
+      ret = session->internals.push_func (fd, giovec[j].iov_base, 
giovec[j].iov_len);
 
       if (ret == -1)
         break;
@@ -673,7 +616,8 @@ _gnutls_io_read_buffered (gnutls_session_t session, size_t 
total,
    * select think, that the socket is ready for reading.
    * MSG_PEEK is only used with berkeley style sockets.
    */
-  if (ret == readsize && recvlowat > 0 && !_gnutls_is_dtls(session))
+  if (ret == readsize && recvlowat > 0 && !_gnutls_is_dtls(session) && 
+    session->internals.pull_func == system_read)
     {
       ret2 = _gnutls_read (session, &bufel, recvlowat, system_read_peek);
 
@@ -844,13 +788,16 @@ _gnutls_io_write_flush (gnutls_session_t session)
  * on timeout and a negative value on error.
  */
 int
-_gnutls_io_check_recv (gnutls_session_t session, int ms)
+_gnutls_io_check_recv (gnutls_session_t session, void* data, size_t data_size, 
unsigned int ms)
 {
   gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
   int ret;
   
-  
-  ret = system_recv_timeout(fd, ms);
+  if (session->internals.pull_timeout_func == system_recv_timeout && 
+    session->internals.pull_func != system_read)
+    return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
+
+  ret = session->internals.pull_timeout_func(fd, data, data_size, ms);
   if (ret == -1)
     return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
   
@@ -1111,84 +1058,3 @@ _gnutls_handshake_buffer_clear (gnutls_session_t session)
   return 0;
 }
 
-/**
- * gnutls_transport_set_pull_function:
- * @session: is a #gnutls_session_t structure.
- * @pull_func: a callback function similar to read()
- *
- * This is the function where you set a function for gnutls to receive
- * data.  Normally, if you use berkeley style sockets, do not need to
- * use this function since the default (recv(2)) will probably be ok.
- *
- * PULL_FUNC is of the form,
- * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);
- **/
-void
-gnutls_transport_set_pull_function (gnutls_session_t session,
-                                    gnutls_pull_func pull_func)
-{
-  session->internals.pull_func = pull_func;
-}
-
-/**
- * gnutls_transport_set_push_function:
- * @session: is a #gnutls_session_t structure.
- * @push_func: a callback function similar to write()
- *
- * This is the function where you set a push function for gnutls to
- * use in order to send data.  If you are going to use berkeley style
- * sockets, you do not need to use this function since the default
- * (send(2)) will probably be ok.  Otherwise you should specify this
- * function for gnutls to be able to send data.
- *
- * PUSH_FUNC is of the form,
- * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
- **/
-void
-gnutls_transport_set_push_function (gnutls_session_t session,
-                                    gnutls_push_func push_func)
-{
-  session->internals.push_func = push_func;
-  session->internals.vec_push_func = NULL;
-}
-
-/**
- * gnutls_transport_set_push_function2:
- * @session: is a #gnutls_session_t structure.
- * @vec_func: a callback function similar to writev()
- *
- * This is the function where you set a push function for gnutls to
- * use in order to send data.  If you are going to use berkeley style
- * sockets, you do not need to use this function since the default
- * (send(2)) will probably be ok.  Otherwise you should specify this
- * function for gnutls to be able to send data.
- *
- * PUSH_FUNC is of the form,
- * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
- **/
-void
-gnutls_transport_set_push_function2 (gnutls_session_t session,
-                                     gnutls_vec_push_func vec_func)
-{
-  session->internals.push_func = NULL;
-  session->internals.vec_push_func = vec_func;
-}
-
-/**
- * gnutls_transport_set_errno_function:
- * @session: is a #gnutls_session_t structure.
- * @errno_func: a callback function similar to write()
- *
- * This is the function where you set a function to retrieve errno
- * after a failed push or pull operation.
- *
- * errno_func is of the form,
- * int (*gnutls_errno_func)(gnutls_transport_ptr_t);
- * and should return the errno.
- **/
-void
-gnutls_transport_set_errno_function (gnutls_session_t session,
-                                     gnutls_errno_func errno_func)
-{
-  session->internals.errno_func = errno_func;
-}
diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h
index 8028f73..37371ba 100644
--- a/lib/gnutls_buffers.h
+++ b/lib/gnutls_buffers.h
@@ -60,7 +60,8 @@ int _gnutls_handshake_io_cache_int (gnutls_session_t,
                                      gnutls_handshake_description_t,
                                      mbuffer_st * bufel);
 ssize_t _gnutls_io_write_flush (gnutls_session_t session);
-int _gnutls_io_check_recv (gnutls_session_t session, int ms);
+int
+_gnutls_io_check_recv (gnutls_session_t session, void* data, size_t data_size, 
unsigned int ms);
 ssize_t _gnutls_handshake_io_write_flush (gnutls_session_t session);
 
 #endif
diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c
index aadb110..9e25d32 100644
--- a/lib/gnutls_constate.c
+++ b/lib/gnutls_constate.c
@@ -677,6 +677,7 @@ epoch_get_slot (gnutls_session_t session, uint16_t epoch)
 
   if (epoch_index >= MAX_EPOCH_INDEX)
     {
+      _gnutls_dtls_log("Epoch %d out of range (idx: %d, max: %d)\n", 
(int)epoch, (int)epoch_index, MAX_EPOCH_INDEX);
       gnutls_assert ();
       return NULL;
     }
@@ -746,9 +747,19 @@ epoch_alive (gnutls_session_t session, 
record_parameters_st * params)
   const security_parameters_st *sp = &session->security_parameters;
 
   /* DTLS will, in addition, need to check the epoch timeout value. */
-  return (params->epoch == sp->epoch_read
-          || params->epoch == sp->epoch_write
-          || params->epoch == sp->epoch_next);
+  if (params->usage_cnt > 0)
+    return 1;
+
+  if (params->epoch == sp->epoch_read)
+    return 1;
+  
+  if (params->epoch == sp->epoch_write)
+    return 1;
+  
+  if (params->epoch == sp->epoch_next)
+    return 1;
+
+  return 0;
 }
 
 void
diff --git a/lib/gnutls_dtls.c b/lib/gnutls_dtls.c
index b01f92a..fdb8479 100644
--- a/lib/gnutls_dtls.c
+++ b/lib/gnutls_dtls.c
@@ -33,6 +33,7 @@
 #include <gnutls_mbuffers.h>
 #include <gnutls_buffers.h>
 #include <gnutls_constate.h>
+#include <gnutls/dtls.h>
 
 /* This function is called once a handshake message is ready to be
  * queued in the next outgoing flight. The actual transmission occurs
@@ -56,10 +57,7 @@ _gnutls_dtls_handshake_enqueue (gnutls_session_t session,
 
   msg = gnutls_malloc (sizeof(dtls_hsk_retransmit_buffer));
   if (msg == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
+    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
 
   msg->bufel = bufel;
 
@@ -69,9 +67,11 @@ _gnutls_dtls_handshake_enqueue (gnutls_session_t session,
   msg->type = type;
   msg->sequence = sequence;
 
-  _gnutls_dtls_log ("DTLS[%p]: Enqueued Packet[%u] %s(%d) with length: %u\n",
+  params->usage_cnt++;
+
+  _gnutls_dtls_log ("DTLS[%p]: Enqueued Packet[%u] %s(%d) with length: %u on 
epoch %d\n",
                    session, (uint)sequence, _gnutls_handshake2str (type),
-                   type, msg->bufel->msg.size);
+                   type, msg->bufel->msg.size, msg->epoch);
 
   *(session->internals.dtls.retransmit_end) = msg;
   session->internals.dtls.retransmit_end = &msg->next;
@@ -92,10 +92,11 @@ transmit_message (gnutls_session_t session,
 
   if (msg->type == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
     {
-      return _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1,
+      ret = _gnutls_send_int (session, GNUTLS_CHANGE_CIPHER_SPEC, -1,
         msg->epoch, 
         _mbuffer_get_uhead_ptr(msg->bufel), 
         _mbuffer_get_uhead_size(msg->bufel), 0);
+      goto leave_epoch;
     }
 
   mtu_data = gnutls_malloc(mtu + DTLS_HANDSHAKE_HEADER_SIZE);
@@ -118,7 +119,7 @@ transmit_message (gnutls_session_t session,
   _gnutls_write_uint16 (msg->sequence, &mtu_data[4]);
 
   /* Chop up and send handshake message into mtu-size pieces. */
-  for (offset=0; offset < data_size; offset += mtu)
+  for (offset=0; offset <= data_size; offset += mtu)
     {
       /* Calculate fragment length */
       if(offset + mtu > data_size)
@@ -152,9 +153,29 @@ transmit_message (gnutls_session_t session,
    }
 
   gnutls_free (mtu_data);
+leave_epoch:
+
   return ret;
 }
 
+static int drop_usage_count(gnutls_session_t session)
+{
+  dtls_hsk_retransmit_buffer *msg;
+  record_parameters_st * params;
+  int ret;
+
+  for (msg = session->internals.dtls.retransmit; msg != NULL; msg = msg->next)
+    {
+      ret = _gnutls_epoch_get( session, msg->epoch, &params);
+      if (ret < 0)
+        return gnutls_assert_val(ret);
+      params->usage_cnt--;
+      if (params->usage_cnt < 0)
+        return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+    }
+  return 0;
+}
+
 /* This function transmits the flight that has been previously
  * buffered.
  *
@@ -168,29 +189,65 @@ int ret;
 
   /* PREPARING -> SENDING state transition */
   dtls_hsk_retransmit_buffer *msg;
+  unsigned int total_timeout = 0;
+  gnutls_handshake_description_t last_type = 0;
 
-restart:
-  _gnutls_dtls_log ("DTLS[%p]: Start of flight transmission.\n", session);
+  do 
+    {
+      _gnutls_dtls_log ("DTLS[%p]: Start of flight transmission.\n", session);
 
-  for (msg = session->internals.dtls.retransmit; msg != NULL; msg = msg->next)
-    transmit_message (session, msg);
+      for (msg = session->internals.dtls.retransmit; msg != NULL; msg = 
msg->next)
+        {
+          transmit_message (session, msg);
+          last_type = msg->type;
+        }
 
-  ret = _gnutls_io_write_flush (session);
-  if (ret < 0)
-    return gnutls_assert_val(ret);
+      ret = _gnutls_io_write_flush (session);
+      if (ret < 0)
+        return gnutls_assert_val(ret);
+
+      /* last message in handshake -> no ack */
+      if (session->security_parameters.entity == GNUTLS_SERVER &&
+        last_type == GNUTLS_HANDSHAKE_FINISHED)
+        {
+          opaque c;
+          ret = _gnutls_io_check_recv(session, &c, 1, 
session->internals.dtls.retrans_timeout);
+          if (ret == GNUTLS_E_TIMEDOUT)
+            ret = 0;
+          else if (ret >= 0)
+            {
+              if (c == GNUTLS_HANDSHAKE) /* retransmit */
+                ret = GNUTLS_E_TIMEDOUT;
+            }
+          total_timeout += session->internals.dtls.retrans_timeout;
+        }
+      else /* all other messages -> implicit ack (receive of next flight) */
+        {
+          ret = _gnutls_io_check_recv(session, NULL, 0, 
session->internals.dtls.retrans_timeout);
+          total_timeout += session->internals.dtls.retrans_timeout;
+        }
+
+      if (total_timeout >= session->internals.dtls.total_timeout) {
+        ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
+        goto cleanup;
+      }
+    } while(ret == GNUTLS_E_TIMEDOUT);
 
-  ret = _gnutls_io_check_recv(session, 100);
-  if (ret == GNUTLS_E_TIMEDOUT)
-    goto restart;
-  else if (ret < 0)
-    return gnutls_assert_val(ret);
+  if (ret < 0)
+    {
+      ret = gnutls_assert_val(ret);
+      goto cleanup;
+    }
 
   _gnutls_dtls_log ("DTLS[%p]: End of flight transmission.\n", session);
+  ret = 0;
 
+cleanup:
+  drop_usage_count(session);
   _gnutls_dtls_clear_outgoing_buffer (session);
 
   /* SENDING -> WAITING state transition */
-  return 0;
+  return ret;
 }
 
 /* This function clears the outgoing flight buffer. */
@@ -215,14 +272,25 @@ _gnutls_dtls_clear_outgoing_buffer (gnutls_session_t 
session)
   session->internals.dtls.retransmit = NULL;
 }
 
-#if 0
-void
-_gnutls_dtls_split_sequence (const uint64 *input,
-                            uint16_t *epoch, uint64_t *sequence)
+/**
+ * gnutls_dtls_set_timeouts:
+ * @session: is a #gnutls_session_t structure.
+ * @retrans_timeout: The time at which a retransmission will occur in 
milliseconds
+ * @total_timeout: The time at which the connection will be aborted, in 
milliseconds.
+ *
+ * This function will set the timeouts required for the DTLS handshake
+ * protocol. The retransmission timeout is the time after which a
+ * message from the peer is not received, the previous messages will
+ * be retransmitted. The total timeout is the time after which the
+ * handshake will be aborted with %GNUTLS_E_TIMEDOUT.
+ *
+ * If the retransmission timeout is zero then the handshake will operate
+ * in a non-blocking way, i.e., return %GNUTLS_E_AGAIN.
+ *
+ **/
+void gnutls_dtls_set_timeouts (gnutls_session_t session, unsigned int 
retrans_timeout,
+  unsigned int total_timeout)
 {
-  *epoch = _gnutls_read_uint16 (UINT64DATA(*input));
-  *sequence = _gnutls_read_uint48 (&UINT64DATA(*input)[2]);
-
-//  fprintf(stderr, "%04x:%012lx\n", *epoch, *sequence);
+  session->internals.dtls.retrans_timeout  = retrans_timeout;
+  session->internals.dtls.total_timeout  = total_timeout;
 }
-#endif
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index 95de0f4..b5811c0 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -319,6 +319,8 @@ static const gnutls_error_entry error_algorithms[] = {
                GNUTLS_E_PKCS11_TOKEN_ERROR, 1),
   ERROR_ENTRY (N_("PKCS #11 user error"),
                GNUTLS_E_PKCS11_USER_ERROR, 1),
+  ERROR_ENTRY (N_("The operation timed out"),
+               GNUTLS_E_TIMEDOUT, 1),
   {NULL, NULL, 0, 0}
 };
 
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 9889c3b..454232b 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -518,6 +518,16 @@ _gnutls_read_client_hello (gnutls_session_t session, 
opaque * data,
       session->internals.resumed = RESUME_FALSE;
     }
 
+  if (_gnutls_is_dtls(session))
+   {
+     int cookie_size;
+
+     DECR_LEN (len, 1);
+     cookie_size = data[pos++];
+     DECR_LEN (len, cookie_size);
+     pos+=cookie_size;
+   }
+
   /* Remember ciphersuites for later
    */
   DECR_LEN (len, 2);
@@ -943,31 +953,20 @@ _gnutls_server_select_suite (gnutls_session_t session, 
opaque * data,
       gnutls_assert ();
       return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
     }
-#ifdef HANDSHAKE_DEBUG
 
-  _gnutls_handshake_log ("HSK[%p]: Requested cipher suites: \n", session);
-  for (j = 0; j < datalen; j += 2)
-    {
-      memcpy (&cs.suite, &data[j], 2);
-      _gnutls_handshake_log ("\t%s\n", _gnutls_cipher_suite_get_name (&cs));
-    }
-  _gnutls_handshake_log ("HSK[%p]: Supported cipher suites: \n", session);
-  for (j = 0; j < x; j++)
-    _gnutls_handshake_log ("\t%s\n",
-                           _gnutls_cipher_suite_get_name (&ciphers[j]));
-#endif
-  memset (session->security_parameters.current_cipher_suite.suite, '\0', 2);
+  memset (session->security_parameters.current_cipher_suite.suite, 0, 2);
 
   retval = GNUTLS_E_UNKNOWN_CIPHER_SUITE;
 
+  _gnutls_handshake_log ("HSK[%p]: Requested cipher suites[size: %d]: \n", 
session, (int)datalen);
   for (j = 0; j < datalen; j += 2)
     {
+      memcpy (&cs.suite, &data[j], 2);
+      _gnutls_handshake_log ("\t0x%.2x, 0x%.2x %s\n", data[j], data[j+1], 
_gnutls_cipher_suite_get_name (&cs));
       for (i = 0; i < x; i++)
         {
           if (memcmp (ciphers[i].suite, &data[j], 2) == 0)
             {
-              memcpy (&cs.suite, &data[j], 2);
-
               _gnutls_handshake_log
                 ("HSK[%p]: Selected cipher suite: %s\n", session,
                  _gnutls_cipher_suite_get_name (&cs));
@@ -1212,7 +1211,7 @@ _gnutls_send_handshake (gnutls_session_t session, 
mbuffer_st * bufel,
       pos += 3;
     }
 
-  _gnutls_handshake_log ("HSK[%p]: %s was sent [%ld bytes]\n",
+  _gnutls_handshake_log ("HSK[%p]: %s was queued [%ld bytes]\n",
                          session, _gnutls_handshake2str (type),
                          (long) datasize);
 
@@ -1240,7 +1239,7 @@ _gnutls_send_handshake (gnutls_session_t session, 
mbuffer_st * bufel,
          _gnutls_handshake_hash_add_sent (session, type, data, datasize)) < 0)
       {
         gnutls_assert ();
-      _mbuffer_xfree(&bufel);
+        _mbuffer_xfree(&bufel);
         return ret;
       }
 
@@ -1418,6 +1417,9 @@ _gnutls_recv_handshake_header (gnutls_session_t session,
     return length32;
   else if (*recv_type != type)
     {
+      _gnutls_handshake_log ("HSK[%p]: %s was received, expected %s\n",
+                             session, _gnutls_handshake2str (*recv_type),
+                              _gnutls_handshake2str (type));
       gnutls_assert ();
       return GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET;
     }
@@ -1604,7 +1606,7 @@ _gnutls_recv_handshake (gnutls_session_t session, uint8_t 
** data,
       else
        /* Signal our caller we have received a verification cookie
           and ClientHello needs to be sent again. */
-       ret = 1;
+        ret = 1;
        
       goto cleanup; /* caller doesn't need dataptr */
 
@@ -2282,7 +2284,7 @@ _gnutls_send_client_hello (gnutls_session_t session, int 
again)
     _gnutls_send_handshake (session, bufel, GNUTLS_HANDSHAKE_CLIENT_HELLO);
 
 cleanup:
-  gnutls_free (bufel);
+  _mbuffer_xfree(&bufel);
   _gnutls_buffer_clear(&extdata);
   return ret;
 }
@@ -2870,20 +2872,20 @@ _gnutls_handshake_client (gnutls_session_t session)
 
     case STATE11:
       if (_gnutls_is_dtls (session))
-       {
-         ret =
-           _gnutls_recv_handshake (session, NULL, NULL,
-                                   GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST,
-                                   OPTIONAL_PACKET);
-         STATE = STATE11;
-         IMED_RET ("recv hello verify", ret, 1);
-
-         if (ret == 1)
-           {
-             STATE = STATE0;
-             return 1;
-           }
-       }
+        {
+          ret =
+            _gnutls_recv_handshake (session, NULL, NULL,
+                  GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST,
+                  OPTIONAL_PACKET);
+          STATE = STATE11;
+          IMED_RET ("recv hello verify", ret, 1);
+
+          if (ret == 1)
+            {
+              STATE = STATE0;
+              return 1;
+            }
+        }
     case STATE2:
       /* receive the server hello */
       ret =
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 20d7422..d3da01d 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -491,6 +491,12 @@ struct record_parameters_st
 
   record_state_st read;
   record_state_st write;
+  
+  /* Whether this state is in use, i.e., if there is
+     a pending handshake message waiting to be encrypted
+     under this epoch's parameters.
+   */
+  int usage_cnt;
 };
 
 typedef struct
@@ -559,6 +565,9 @@ typedef struct
   uint16_t hsk_read_seq;
   uint16_t hsk_mtu;
 
+  unsigned int retrans_timeout;
+  unsigned int total_timeout;
+
   /* Head of the next outgoing flight. */
   dtls_hsk_retransmit_buffer *retransmit;
   dtls_hsk_retransmit_buffer **retransmit_end;
@@ -700,6 +709,7 @@ typedef struct
 
   /* PUSH & PULL functions.
    */
+  gnutls_pull_timeout_func pull_timeout_func;
   gnutls_pull_func pull_func;
   gnutls_push_func push_func;
   gnutls_vec_push_func vec_push_func;
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index d1f0742..ab2350e 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -48,6 +48,7 @@
 #include <gnutls_rsa_export.h>
 #include <gnutls_extensions.h>
 #include <system.h>
+#include <gnutls/dtls.h>
 
 /* These should really be static, but src/tests.c calls them.  Make
    them public functions?  */
@@ -371,6 +372,7 @@ gnutls_init (gnutls_session_t * session, 
gnutls_connection_end_t con_end)
 #endif
   gnutls_transport_set_pull_function (*session, system_read);
   gnutls_transport_set_errno_function (*session, system_errno);
+  gnutls_transport_set_pull_timeout_function (*session, system_recv_timeout);
 
   return 0;
 }
@@ -406,6 +408,9 @@ gnutls_init_dtls (gnutls_session_t * session,
   /* Initialize pointer used to enqueue messages for retransmit. */
   (*session)->internals.dtls.retransmit_end = 
&(*session)->internals.dtls.retransmit;
 
+  (*session)->internals.dtls.retrans_timeout = 1000;
+  (*session)->internals.dtls.total_timeout = 4000;
+
   return 0;
 }
 
diff --git a/lib/ext_srp.h b/lib/includes/gnutls/dtls.h
similarity index 58%
copy from lib/ext_srp.h
copy to lib/includes/gnutls/dtls.h
index 9ebcf23..db391d9 100644
--- a/lib/ext_srp.h
+++ b/lib/includes/gnutls/dtls.h
@@ -1,6 +1,5 @@
 /*
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2010 Free Software
- * Foundation, Inc.
+ * Copyright (C) 2011 Free Software Foundation, Inc.
  *
  * Author: Nikos Mavrogiannopoulos
  *
@@ -18,29 +17,35 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
  * USA
  *
  */
 
-#ifndef EXT_SRP_H
-#define EXT_SRP_H
+/* This file contains the types and prototypes for the X.509
+ * certificate and CRL handling functions.
+ */
 
-#include <gnutls_extensions.h>
+#ifndef GNUTLS_DTLS_H
+#define GNUTLS_DTLS_H
 
-#ifdef ENABLE_SRP
+#include <gnutls/gnutls.h>
 
-#define IS_SRP_KX(kx) ((kx == GNUTLS_KX_SRP || (kx == GNUTLS_KX_SRP_RSA) || \
-          kx == GNUTLS_KX_SRP_DSS)?1:0)
+#ifdef __cplusplus
+extern "C"
+{
+#endif
 
-extern extension_entry_st ext_mod_srp;
+int gnutls_init_dtls (gnutls_session_t * session,
+                       gnutls_connection_end_t con_end,
+                       gnutls_dtls_flags_t flags);
 
-typedef struct
-{
-  char *username;
-  char *password;
-} srp_ext_st;
+void gnutls_dtls_set_timeouts (gnutls_session_t session, unsigned int 
retrans_timeout,
+  unsigned int total_timeout);
 
+#ifdef __cplusplus
+}
 #endif
 
-#endif
+#endif                          /* GNUTLS_DTLS_H */
+
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 7518c24..ebe09bd 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -689,9 +689,6 @@ extern "C"
 
   int gnutls_init (gnutls_session_t * session,
                    gnutls_connection_end_t con_end);
-  int gnutls_init_dtls (gnutls_session_t * session,
-                       gnutls_connection_end_t con_end,
-                       gnutls_dtls_flags_t flags);
   void gnutls_deinit (gnutls_session_t session);
 #define _gnutls_deinit(x) gnutls_deinit(x)
 
@@ -1187,6 +1184,8 @@ extern "C"
   typedef ssize_t (*gnutls_push_func) (gnutls_transport_ptr_t, const void *,
                                        size_t);
 
+  typedef int (*gnutls_pull_timeout_func) (gnutls_transport_ptr_t, void*data, 
size_t size, unsigned int ms);
+
   typedef ssize_t (*gnutls_vec_push_func) (gnutls_transport_ptr_t,
                                            const giovec_t * iov, int iovcnt);
 
@@ -1213,6 +1212,9 @@ extern "C"
   void gnutls_transport_set_pull_function (gnutls_session_t session,
                                            gnutls_pull_func pull_func);
 
+  void gnutls_transport_set_pull_timeout_function (gnutls_session_t session,
+                                            gnutls_pull_timeout_func func);
+
   void gnutls_transport_set_errno_function (gnutls_session_t session,
                                             gnutls_errno_func errno_func);
 
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 945b45d..5576c5a 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -625,7 +625,6 @@ GNUTLS_2_12
        gnutls_pkcs11_privkey_decrypt_data;
        gnutls_pkcs11_obj_export;
        gnutls_pkcs11_type_get_name;
-
        gnutls_privkey_init;
        gnutls_privkey_deinit;
        gnutls_privkey_get_pk_algorithm;
@@ -667,7 +666,6 @@ GNUTLS_2_12
        gnutls_global_set_mutex;
         gnutls_transport_set_push_function2;
         gnutls_transport_set_errno_function;
-
        gnutls_sec_param_to_pk_bits;
        gnutls_sec_param_get_name;
        gnutls_pk_bits_to_sec_param;
@@ -687,6 +685,10 @@ GNUTLS_2_12
        gnutls_openpgp_crt_verify_hash;
        gnutls_pubkey_import_privkey;
        gnutls_pubkey_verify_data;
+} GNUTLS_2_10;
+
+GNUTLS_3_0_0 {
+  global:
        gnutls_x509_trust_list_verify_crt;
        gnutls_x509_trust_list_add_crls;
        gnutls_x509_trust_list_add_cas;
@@ -697,7 +699,9 @@ GNUTLS_2_12
        gnutls_x509_crt_list_import2;
        gnutls_cipher_tag;
        gnutls_cipher_add_auth;
-} GNUTLS_2_10;
+       gnutls_dtls_set_timeouts;
+       gnutls_transport_set_pull_timeout_function;
+} GNUTLS_2_12;
 
 GNUTLS_PRIVATE {
   global:
diff --git a/lib/system.c b/lib/system.c
index d89c283..169dd15 100644
--- a/lib/system.c
+++ b/lib/system.c
@@ -105,12 +105,15 @@ system_read_peek (gnutls_transport_ptr ptr, void *data, 
size_t data_size)
   return recv (GNUTLS_POINTER_TO_INT (ptr), data, data_size, MSG_PEEK);
 }
 
-/* Wait for data to be received within a timeout period in milliseconds
+/* Wait for data to be received within a timeout period in milliseconds.
+ * If data_size > 0 it will return the specified amount of data in
+ * peek mode.
  */
-int system_recv_timeout(gnutls_transport_ptr ptr, size_t ms)
+int system_recv_timeout(gnutls_transport_ptr ptr, void* data, size_t 
data_size, unsigned int ms)
 {
 fd_set rfds;
 struct timeval tv;
+int ret;
 
   FD_ZERO(&rfds);
   FD_SET(GNUTLS_POINTER_TO_INT(ptr), &rfds);
@@ -118,7 +121,23 @@ struct timeval tv;
   tv.tv_sec = 0;
   tv.tv_usec = ms * 1000;
   
-  return select(GNUTLS_POINTER_TO_INT(ptr)+1, &rfds, NULL, NULL, &tv);
+  ret = select(GNUTLS_POINTER_TO_INT(ptr)+1, &rfds, NULL, NULL, &tv);
+
+  if (ret <= 0 || data_size == 0)
+    return ret;
+
+  /* only report ok if the next message is from the peer we expect
+   * from 
+   */
+  ret = recv(GNUTLS_POINTER_TO_INT(ptr), data, data_size, MSG_PEEK);
+  if (ret > 0)
+    {
+      return ret;
+    }
+  else
+    {
+       return -1;
+    }
 }
 
 /* Thread stuff */
diff --git a/lib/system.h b/lib/system.h
index 6ec4e83..207e6fa 100644
--- a/lib/system.h
+++ b/lib/system.h
@@ -8,7 +8,7 @@
 #endif
 
 int system_errno (gnutls_transport_ptr);
-int system_recv_timeout(gnutls_transport_ptr ptr, size_t ms);
+int system_recv_timeout(gnutls_transport_ptr ptr,void*data, size_t, unsigned 
int ms);
 
 #ifdef _WIN32
 ssize_t system_write (gnutls_transport_ptr ptr, const void *data,
diff --git a/lib/system_override.c b/lib/system_override.c
new file mode 100644
index 0000000..852ec2b
--- /dev/null
+++ b/lib/system_override.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ * 2009, 2010, 2011 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* This file contains function that will override the 
+ * default berkeley sockets API per session.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_num.h>
+#include <gnutls_record.h>
+#include <gnutls_buffers.h>
+#include <gnutls_mbuffers.h>
+#include <gnutls_state.h>
+#include <gnutls_dtls.h>
+#include <system.h>
+
+#include <errno.h>
+
+/**
+ * gnutls_transport_set_errno:
+ * @session: is a #gnutls_session_t structure.
+ * @err: error value to store in session-specific errno variable.
+ *
+ * Store @err in the session-specific errno variable.  Useful values
+ * for @err is EAGAIN and EINTR, other values are treated will be
+ * treated as real errors in the push/pull function.
+ *
+ * This function is useful in replacement push/pull functions set by
+ * gnutls_transport_set_push_function and
+ * gnutls_transport_set_pullpush_function under Windows, where the
+ * replacement push/pull may not have access to the same @errno
+ * variable that is used by GnuTLS (e.g., the application is linked to
+ * msvcr71.dll and gnutls is linked to msvcrt.dll).
+ *
+ * If you don't have the @session variable easily accessible from the
+ * push/pull function, and don't worry about thread conflicts, you can
+ * also use gnutls_transport_set_global_errno().
+ **/
+void
+gnutls_transport_set_errno (gnutls_session_t session, int err)
+{
+  session->internals.errnum = err;
+}
+
+/**
+ * gnutls_transport_set_global_errno:
+ * @err: error value to store in global errno variable.
+ *
+ * Store @err in the global errno variable.  Useful values for @err is
+ * EAGAIN and EINTR, other values are treated will be treated as real
+ * errors in the push/pull function.
+ *
+ * This function is useful in replacement push/pull functions set by
+ * gnutls_transport_set_push_function and
+ * gnutls_transport_set_pullpush_function under Windows, where the
+ * replacement push/pull may not have access to the same @errno
+ * variable that is used by GnuTLS (e.g., the application is linked to
+ * msvcr71.dll and gnutls is linked to msvcrt.dll).
+ *
+ * Whether this function is thread safe or not depends on whether the
+ * global variable errno is thread safe, some system libraries make it
+ * a thread-local variable.  When feasible, using the guaranteed
+ * thread-safe gnutls_transport_set_errno() may be better.
+ **/
+void
+gnutls_transport_set_global_errno (int err)
+{
+  errno = err;
+}
+
+/**
+ * gnutls_transport_set_pull_function:
+ * @session: is a #gnutls_session_t structure.
+ * @pull_func: a callback function similar to read()
+ *
+ * This is the function where you set a function for gnutls to receive
+ * data.  Normally, if you use berkeley style sockets, do not need to
+ * use this function since the default (recv(2)) will probably be ok.
+ *
+ * gnutls_pull_func is of the form,
+ * ssize_t (*gnutls_pull_func)(gnutls_transport_ptr_t, void*, size_t);
+ **/
+void
+gnutls_transport_set_pull_function (gnutls_session_t session,
+                                    gnutls_pull_func pull_func)
+{
+  session->internals.pull_func = pull_func;
+}
+
+/**
+ * gnutls_transport_set_pull_timeout_function:
+ * @session: is a #gnutls_session_t structure.
+ * @func: a callback function
+ *
+ * This is the function where you set a function for gnutls to know
+ * whether data are ready to be received within a time limit in
+ * milliseconds. The callback should return 0 on timeout, a positive
+ * number if data can be received, and -1 on error.
+ * If the #data_size is non-zero that function should copy that
+ * amount of data received in peek mode (i.e., if any other
+ * function is called to receive data, it should return them again).
+ *
+ * The callback function is used in DTLS only.
+ *
+ * gnutls_pull_timeout_func is of the form,
+ * ssize_t (*gnutls_pull_timeout_func)(gnutls_transport_ptr_t, void*data, 
size_t size, unsigned int ms);
+ *
+ **/
+void
+gnutls_transport_set_pull_timeout_function (gnutls_session_t session,
+                                    gnutls_pull_timeout_func func)
+{
+  session->internals.pull_timeout_func = func;
+}
+
+/**
+ * gnutls_transport_set_push_function:
+ * @session: is a #gnutls_session_t structure.
+ * @push_func: a callback function similar to write()
+ *
+ * This is the function where you set a push function for gnutls to
+ * use in order to send data.  If you are going to use berkeley style
+ * sockets, you do not need to use this function since the default
+ * (send(2)) will probably be ok.  Otherwise you should specify this
+ * function for gnutls to be able to send data.
+ *
+ * push_func is of the form,
+ * ssize_t (*gnutls_push_func)(gnutls_transport_ptr_t, const void*, size_t);
+ *
+ **/
+void
+gnutls_transport_set_push_function (gnutls_session_t session,
+                                    gnutls_push_func push_func)
+{
+  session->internals.push_func = push_func;
+  session->internals.vec_push_func = NULL;
+}
+
+/**
+ * gnutls_transport_set_push_function2:
+ * @session: is a #gnutls_session_t structure.
+ * @vec_func: a callback function similar to writev()
+ *
+ * This is the function where you set a push function for gnutls to
+ * use in order to send data.  If you are going to use berkeley style
+ * sockets, you do not need to use this function since the default
+ * (send(2)) will probably be ok.  Otherwise you should specify this
+ * function for gnutls to be able to send data.
+ *
+ * vec_func is of the form,
+ * ssize_t (*gnutls_vec_push_func) (gnutls_transport_ptr_t, const giovec_t * 
iov, int iovcnt);
+ *
+ **/
+void
+gnutls_transport_set_push_function2 (gnutls_session_t session,
+                                     gnutls_vec_push_func vec_func)
+{
+  session->internals.push_func = NULL;
+  session->internals.vec_push_func = vec_func;
+}
+
+/**
+ * gnutls_transport_set_errno_function:
+ * @session: is a #gnutls_session_t structure.
+ * @errno_func: a callback function similar to write()
+ *
+ * This is the function where you set a function to retrieve errno
+ * after a failed push or pull operation.
+ *
+ * errno_func is of the form,
+ * int (*gnutls_errno_func)(gnutls_transport_ptr_t);
+ * and should return the errno.
+ **/
+void
+gnutls_transport_set_errno_function (gnutls_session_t session,
+                                     gnutls_errno_func errno_func)
+{
+  session->internals.errno_func = errno_func;
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 509a446..622ee8c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -40,7 +40,7 @@ endif
 
 noinst_LTLIBRARIES =
 
-gnutls_serv_SOURCES = list.h serv.c common.h common.c certtool-common.h
+gnutls_serv_SOURCES = list.h serv.c udp-serv.c common.h common.c 
certtool-common.h
 gnutls_serv_LDADD = ../lib/libgnutls.la ../libextra/libgnutls-extra.la
 gnutls_serv_LDADD += libcmd-serv.la ../gl/libgnu.la
 gnutls_serv_LDADD += $(LTLIBGCRYPT) $(LIBSOCKET) $(GETADDRINFO_LIB)
diff --git a/src/cli.c b/src/cli.c
index 6f8339b..5df49f8 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -34,6 +34,7 @@
 #include <error.h>
 
 #include <gnutls/gnutls.h>
+#include <gnutls/dtls.h>
 #include <gnutls/extra.h>
 #include <gnutls/x509.h>
 #include <gnutls/openpgp.h>
diff --git a/src/serv-gaa.c b/src/serv-gaa.c
index a3c050d..e1fd2ec 100644
--- a/src/serv-gaa.c
+++ b/src/serv-gaa.c
@@ -133,6 +133,7 @@ void gaa_help(void)
        __gaa_helpsingle(0, "noticket", "", "Does not issue session tickets.");
        __gaa_helpsingle(0, "http", "", "Act as an HTTP Server.");
        __gaa_helpsingle(0, "echo", "", "Act as an Echo Server.");
+       __gaa_helpsingle(0, "udp", "", "Enable UDP server instead of TCP.");
        __gaa_helpsingle(0, "dhparams", "FILE ", "DH params file to use.");
        __gaa_helpsingle(0, "x509fmtder", "", "Use DER format for 
certificates");
        __gaa_helpsingle(0, "x509cafile", "FILE ", "Certificate file or PKCS 
#11 URL to use.");
@@ -169,44 +170,46 @@ typedef struct _gaainfo gaainfo;
 
 struct _gaainfo
 {
-#line 88 "serv.gaa"
+#line 91 "serv.gaa"
        char *priorities;
-#line 85 "serv.gaa"
+#line 88 "serv.gaa"
        char *srp_passwd_conf;
-#line 82 "serv.gaa"
+#line 85 "serv.gaa"
        char *srp_passwd;
-#line 79 "serv.gaa"
+#line 82 "serv.gaa"
        char *psk_hint;
-#line 76 "serv.gaa"
+#line 79 "serv.gaa"
        char *psk_passwd;
-#line 73 "serv.gaa"
+#line 76 "serv.gaa"
        int disable_client_cert;
-#line 70 "serv.gaa"
+#line 73 "serv.gaa"
        int require_cert;
-#line 67 "serv.gaa"
+#line 70 "serv.gaa"
        char *x509_dsacertfile;
-#line 64 "serv.gaa"
+#line 67 "serv.gaa"
        char *x509_dsakeyfile;
-#line 61 "serv.gaa"
+#line 64 "serv.gaa"
        char *x509_certfile;
-#line 58 "serv.gaa"
+#line 61 "serv.gaa"
        char *x509_keyfile;
-#line 55 "serv.gaa"
+#line 58 "serv.gaa"
        char *pgp_subkey;
-#line 52 "serv.gaa"
+#line 55 "serv.gaa"
        char *pgp_certfile;
-#line 49 "serv.gaa"
+#line 52 "serv.gaa"
        char *pgp_keyfile;
-#line 46 "serv.gaa"
+#line 49 "serv.gaa"
        char *pgp_keyring;
-#line 43 "serv.gaa"
+#line 46 "serv.gaa"
        char *x509_crlfile;
-#line 40 "serv.gaa"
+#line 43 "serv.gaa"
        char *x509_cafile;
-#line 37 "serv.gaa"
+#line 40 "serv.gaa"
        int fmtder;
-#line 34 "serv.gaa"
+#line 37 "serv.gaa"
        char *dh_params_file;
+#line 34 "serv.gaa"
+       int udp;
 #line 30 "serv.gaa"
        int http;
 #line 27 "serv.gaa"
@@ -275,7 +278,7 @@ static int gaa_error = 0;
 #define GAA_MULTIPLE_OPTION     3
 
 #define GAA_REST                0
-#define GAA_NB_OPTION           30
+#define GAA_NB_OPTION           31
 #define GAAOPTID_version       1
 #define GAAOPTID_help  2
 #define GAAOPTID_list  3
@@ -298,14 +301,15 @@ static int gaa_error = 0;
 #define GAAOPTID_x509cafile    20
 #define GAAOPTID_x509fmtder    21
 #define GAAOPTID_dhparams      22
-#define GAAOPTID_echo  23
-#define GAAOPTID_http  24
-#define GAAOPTID_noticket      25
-#define GAAOPTID_nodb  26
-#define GAAOPTID_quiet 27
-#define GAAOPTID_port  28
-#define GAAOPTID_generate      29
-#define GAAOPTID_debug 30
+#define GAAOPTID_udp   23
+#define GAAOPTID_echo  24
+#define GAAOPTID_http  25
+#define GAAOPTID_noticket      26
+#define GAAOPTID_nodb  27
+#define GAAOPTID_quiet 28
+#define GAAOPTID_port  29
+#define GAAOPTID_generate      30
+#define GAAOPTID_debug 31
 
 #line 168 "gaa.skel"
 
@@ -655,6 +659,7 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECK1STR("a", GAAOPTID_disable_client_cert);
                        GAA_CHECK1STR("r", GAAOPTID_require_cert);
                        GAA_CHECK1STR("", GAAOPTID_x509fmtder);
+                       GAA_CHECK1STR("", GAAOPTID_udp);
                        GAA_CHECK1STR("", GAAOPTID_echo);
                        GAA_CHECK1STR("", GAAOPTID_http);
                        GAA_CHECK1STR("", GAAOPTID_noticket);
@@ -687,6 +692,7 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECKSTR("x509cafile", GAAOPTID_x509cafile);
                        GAA_CHECKSTR("x509fmtder", GAAOPTID_x509fmtder);
                        GAA_CHECKSTR("dhparams", GAAOPTID_dhparams);
+                       GAA_CHECKSTR("udp", GAAOPTID_udp);
                        GAA_CHECKSTR("echo", GAAOPTID_echo);
                        GAA_CHECKSTR("http", GAAOPTID_http);
                        GAA_CHECKSTR("noticket", GAAOPTID_noticket);
@@ -747,21 +753,21 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
     {
        case GAAOPTID_version:
        OK = 0;
-#line 94 "serv.gaa"
+#line 97 "serv.gaa"
 { serv_version(); exit(0); ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_help:
        OK = 0;
-#line 92 "serv.gaa"
+#line 95 "serv.gaa"
 { gaa_help(); exit(0); ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_list:
        OK = 0;
-#line 91 "serv.gaa"
+#line 94 "serv.gaa"
 { print_list(0); exit(0); ;};
 
                return GAA_OK;
@@ -771,7 +777,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_priority.arg1, gaa_getstr, 
GAATMP_priority.size1);
                gaa_index++;
-#line 89 "serv.gaa"
+#line 92 "serv.gaa"
 { gaaval->priorities = GAATMP_priority.arg1 ;};
 
                return GAA_OK;
@@ -781,7 +787,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_srppasswdconf.arg1, gaa_getstr, 
GAATMP_srppasswdconf.size1);
                gaa_index++;
-#line 86 "serv.gaa"
+#line 89 "serv.gaa"
 { gaaval->srp_passwd_conf = GAATMP_srppasswdconf.arg1 ;};
 
                return GAA_OK;
@@ -791,7 +797,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_srppasswd.arg1, gaa_getstr, 
GAATMP_srppasswd.size1);
                gaa_index++;
-#line 83 "serv.gaa"
+#line 86 "serv.gaa"
 { gaaval->srp_passwd = GAATMP_srppasswd.arg1 ;};
 
                return GAA_OK;
@@ -801,7 +807,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_pskhint.arg1, gaa_getstr, GAATMP_pskhint.size1);
                gaa_index++;
-#line 80 "serv.gaa"
+#line 83 "serv.gaa"
 { gaaval->psk_hint = GAATMP_pskhint.arg1 ;};
 
                return GAA_OK;
@@ -811,21 +817,21 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_pskpasswd.arg1, gaa_getstr, 
GAATMP_pskpasswd.size1);
                gaa_index++;
-#line 77 "serv.gaa"
+#line 80 "serv.gaa"
 { gaaval->psk_passwd = GAATMP_pskpasswd.arg1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_disable_client_cert:
        OK = 0;
-#line 74 "serv.gaa"
+#line 77 "serv.gaa"
 { gaaval->disable_client_cert = 1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_require_cert:
        OK = 0;
-#line 71 "serv.gaa"
+#line 74 "serv.gaa"
 { gaaval->require_cert = 1 ;};
 
                return GAA_OK;
@@ -835,7 +841,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_x509dsacertfile.arg1, gaa_getstr, 
GAATMP_x509dsacertfile.size1);
                gaa_index++;
-#line 68 "serv.gaa"
+#line 71 "serv.gaa"
 { gaaval->x509_dsacertfile = GAATMP_x509dsacertfile.arg1 ;};
 
                return GAA_OK;
@@ -845,7 +851,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_x509dsakeyfile.arg1, gaa_getstr, 
GAATMP_x509dsakeyfile.size1);
                gaa_index++;
-#line 65 "serv.gaa"
+#line 68 "serv.gaa"
 { gaaval->x509_dsakeyfile = GAATMP_x509dsakeyfile.arg1 ;};
 
                return GAA_OK;
@@ -855,7 +861,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_x509certfile.arg1, gaa_getstr, 
GAATMP_x509certfile.size1);
                gaa_index++;
-#line 62 "serv.gaa"
+#line 65 "serv.gaa"
 { gaaval->x509_certfile = GAATMP_x509certfile.arg1 ;};
 
                return GAA_OK;
@@ -865,7 +871,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_x509keyfile.arg1, gaa_getstr, 
GAATMP_x509keyfile.size1);
                gaa_index++;
-#line 59 "serv.gaa"
+#line 62 "serv.gaa"
 { gaaval->x509_keyfile = GAATMP_x509keyfile.arg1 ;};
 
                return GAA_OK;
@@ -875,7 +881,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_pgpsubkey.arg1, gaa_getstr, 
GAATMP_pgpsubkey.size1);
                gaa_index++;
-#line 56 "serv.gaa"
+#line 59 "serv.gaa"
 { gaaval->pgp_subkey = GAATMP_pgpsubkey.arg1 ;};
 
                return GAA_OK;
@@ -885,7 +891,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_pgpcertfile.arg1, gaa_getstr, 
GAATMP_pgpcertfile.size1);
                gaa_index++;
-#line 53 "serv.gaa"
+#line 56 "serv.gaa"
 { gaaval->pgp_certfile = GAATMP_pgpcertfile.arg1 ;};
 
                return GAA_OK;
@@ -895,7 +901,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_pgpkeyfile.arg1, gaa_getstr, 
GAATMP_pgpkeyfile.size1);
                gaa_index++;
-#line 50 "serv.gaa"
+#line 53 "serv.gaa"
 { gaaval->pgp_keyfile = GAATMP_pgpkeyfile.arg1 ;};
 
                return GAA_OK;
@@ -905,7 +911,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_pgpkeyring.arg1, gaa_getstr, 
GAATMP_pgpkeyring.size1);
                gaa_index++;
-#line 47 "serv.gaa"
+#line 50 "serv.gaa"
 { gaaval->pgp_keyring = GAATMP_pgpkeyring.arg1 ;};
 
                return GAA_OK;
@@ -915,7 +921,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_x509crlfile.arg1, gaa_getstr, 
GAATMP_x509crlfile.size1);
                gaa_index++;
-#line 44 "serv.gaa"
+#line 47 "serv.gaa"
 { gaaval->x509_crlfile = GAATMP_x509crlfile.arg1 ;};
 
                return GAA_OK;
@@ -925,14 +931,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_x509cafile.arg1, gaa_getstr, 
GAATMP_x509cafile.size1);
                gaa_index++;
-#line 41 "serv.gaa"
+#line 44 "serv.gaa"
 { gaaval->x509_cafile = GAATMP_x509cafile.arg1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_x509fmtder:
        OK = 0;
-#line 38 "serv.gaa"
+#line 41 "serv.gaa"
 { gaaval->fmtder = 1 ;};
 
                return GAA_OK;
@@ -942,11 +948,18 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_dhparams.arg1, gaa_getstr, 
GAATMP_dhparams.size1);
                gaa_index++;
-#line 35 "serv.gaa"
+#line 38 "serv.gaa"
 { gaaval->dh_params_file = GAATMP_dhparams.arg1 ;};
 
                return GAA_OK;
                break;
+       case GAAOPTID_udp:
+       OK = 0;
+#line 35 "serv.gaa"
+{ gaaval->udp = 1 ;};
+
+               return GAA_OK;
+               break;
        case GAAOPTID_echo:
        OK = 0;
 #line 32 "serv.gaa"
@@ -1033,7 +1046,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
     if(inited == 0)
     {
 
-#line 98 "serv.gaa"
+#line 101 "serv.gaa"
 { gaaval->generate=0; gaaval->port=5556; gaaval->http=0; gaaval->nodb = 0; 
gaaval->noticket = 0;
        gaaval->x509_cafile = NULL; gaaval->pgp_keyfile=NULL; 
gaaval->pgp_certfile=NULL;
        gaaval->x509_keyfile=NULL; gaaval->x509_certfile=NULL; 
gaaval->x509_crlfile = NULL;
@@ -1042,7 +1055,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
        gaaval->pgp_keyring=NULL; gaaval->fmtder = 0;
        gaaval->disable_client_cert = 0; gaaval->priorities = NULL;
        gaaval->dh_params_file=NULL; gaaval->debug=0; gaaval->require_cert = 0; 
gaaval->psk_passwd = 0;
-       gaaval->pgp_subkey = NULL;;};
+       gaaval->pgp_subkey = NULL; gaaval->udp = 0; ;};
 
     }
     inited = 1;
diff --git a/src/serv-gaa.h b/src/serv-gaa.h
index 2a4a08a..0a1d560 100644
--- a/src/serv-gaa.h
+++ b/src/serv-gaa.h
@@ -8,44 +8,46 @@ typedef struct _gaainfo gaainfo;
 
 struct _gaainfo
 {
-#line 88 "serv.gaa"
+#line 91 "serv.gaa"
        char *priorities;
-#line 85 "serv.gaa"
+#line 88 "serv.gaa"
        char *srp_passwd_conf;
-#line 82 "serv.gaa"
+#line 85 "serv.gaa"
        char *srp_passwd;
-#line 79 "serv.gaa"
+#line 82 "serv.gaa"
        char *psk_hint;
-#line 76 "serv.gaa"
+#line 79 "serv.gaa"
        char *psk_passwd;
-#line 73 "serv.gaa"
+#line 76 "serv.gaa"
        int disable_client_cert;
-#line 70 "serv.gaa"
+#line 73 "serv.gaa"
        int require_cert;
-#line 67 "serv.gaa"
+#line 70 "serv.gaa"
        char *x509_dsacertfile;
-#line 64 "serv.gaa"
+#line 67 "serv.gaa"
        char *x509_dsakeyfile;
-#line 61 "serv.gaa"
+#line 64 "serv.gaa"
        char *x509_certfile;
-#line 58 "serv.gaa"
+#line 61 "serv.gaa"
        char *x509_keyfile;
-#line 55 "serv.gaa"
+#line 58 "serv.gaa"
        char *pgp_subkey;
-#line 52 "serv.gaa"
+#line 55 "serv.gaa"
        char *pgp_certfile;
-#line 49 "serv.gaa"
+#line 52 "serv.gaa"
        char *pgp_keyfile;
-#line 46 "serv.gaa"
+#line 49 "serv.gaa"
        char *pgp_keyring;
-#line 43 "serv.gaa"
+#line 46 "serv.gaa"
        char *x509_crlfile;
-#line 40 "serv.gaa"
+#line 43 "serv.gaa"
        char *x509_cafile;
-#line 37 "serv.gaa"
+#line 40 "serv.gaa"
        int fmtder;
-#line 34 "serv.gaa"
+#line 37 "serv.gaa"
        char *dh_params_file;
+#line 34 "serv.gaa"
+       int udp;
 #line 30 "serv.gaa"
        int http;
 #line 27 "serv.gaa"
diff --git a/src/serv.c b/src/serv.c
index 0687624..698ab50 100644
--- a/src/serv.c
+++ b/src/serv.c
@@ -49,6 +49,7 @@
 #include "read-file.h"
 #include "minmax.h"
 #include "sockets.h"
+#include "udp-serv.h"
 
 /* konqueror cannot handle sending the page in multiple
  * pieces.
@@ -56,7 +57,6 @@
 /* global stuff */
 static int generate = 0;
 static int http = 0;
-static int port = 0;
 static int x509ctype;
 static int debug;
 
@@ -81,6 +81,7 @@ char *dh_params_file;
 char *x509_crlfile = NULL;
 
 gnutls_datum_t session_ticket_key;
+static int tcp_server(const char* name, int port);
 
 /* end of globals */
 
@@ -326,13 +327,15 @@ generate_rsa_params (void)
 
 LIST_DECLARE_INIT (listener_list, listener_item, listener_free);
 
-static gnutls_session_t
-initialize_session (void)
+gnutls_session_t initialize_session (int dtls)
 {
   gnutls_session_t session;
   const char *err;
 
-  gnutls_init (&session, GNUTLS_SERVER);
+  if (dtls)
+    gnutls_init_dtls (&session, GNUTLS_SERVER, 0);
+  else
+    gnutls_init (&session, GNUTLS_SERVER);
 
   /* allow the use of private ciphersuites.
    */
@@ -585,7 +588,7 @@ peer_print_info (gnutls_session_t session, int *ret_length,
   return http_buffer;
 }
 
-static const char *
+const char *
 human_addr (const struct sockaddr *sa, socklen_t salen,
             char *buf, size_t buflen)
 {
@@ -633,8 +636,52 @@ human_addr (const struct sockaddr *sa, socklen_t salen,
   return save_buf;
 }
 
-static int
-listen_socket (const char *name, int listen_port)
+int wait_for_connection(void)
+{
+  listener_item *j;
+  fd_set rd, wr;
+  int n, sock = -1;
+
+  FD_ZERO (&rd);
+  FD_ZERO (&wr);
+  n = 0;
+
+  lloopstart (listener_list, j)
+  {
+    if (j->listen_socket)
+      {
+        FD_SET (j->fd, &rd);
+        n = MAX (n, j->fd);
+      }
+  }
+  lloopend (listener_list, j);
+
+  /* waiting part */
+  n = select (n + 1, &rd, &wr, NULL, NULL);
+  if (n == -1 && errno == EINTR)
+    return -1;
+  if (n < 0)
+    {
+      perror ("select()");
+      exit (1);
+    }
+
+  /* find which one is ready */
+  lloopstart (listener_list, j)
+    {
+      /* a new connection has arrived */
+      if (FD_ISSET (j->fd, &rd) && j->listen_socket)
+        {
+          sock = j->fd;
+          break;
+        }
+    }
+  lloopend (listener_list, j);
+  return sock;
+}
+
+int
+listen_socket (const char *name, int listen_port, int socktype)
 {
   struct addrinfo hints, *res, *ptr;
   char portname[6];
@@ -644,7 +691,7 @@ listen_socket (const char *name, int listen_port)
 
   snprintf (portname, sizeof (portname), "%d", listen_port);
   memset (&hints, 0, sizeof (hints));
-  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_socktype = socktype;
   hints.ai_flags = AI_PASSIVE;
 
   if ((s = getaddrinfo (NULL, portname, &hints, &res)) != 0)
@@ -671,26 +718,32 @@ listen_socket (const char *name, int listen_port)
           continue;
         }
 
-      yes = 1;
-      if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
-                      (const void *) &yes, sizeof (yes)) < 0)
+      if (socktype == SOCK_STREAM)
         {
-          perror ("setsockopt() failed");
-        failed:
-          close (s);
-          continue;
+          yes = 1;
+          if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
+                          (const void *) &yes, sizeof (yes)) < 0)
+            {
+              perror ("setsockopt() failed");
+              close (s);
+              continue;
+            }
         }
 
       if (bind (s, ptr->ai_addr, ptr->ai_addrlen) < 0)
         {
           perror ("bind() failed");
-          goto failed;
+          close (s);
+          continue;
         }
 
-      if (listen (s, 10) < 0)
+      if (socktype == SOCK_STREAM)
         {
-          perror ("listen() failed");
-          goto failed;
+          if (listen (s, 10) < 0)
+            {
+              perror ("listen() failed");
+              exit(1);
+            }
         }
 
       /* new list entry for the connection */
@@ -706,10 +759,8 @@ listen_socket (const char *name, int listen_port)
   fflush (stderr);
 
   freeaddrinfo (res);
-  if (!j)
-    return -1;
 
-  return 0;
+  return s;
 }
 
 /* strips \r\n from the end of the string 
@@ -824,12 +875,8 @@ static void gaa_parser (int argc, char **argv);
 int
 main (int argc, char **argv)
 {
-  int ret, n;
-  char topbuf[512];
+  int ret;
   char name[256];
-  int accept_fd;
-  struct sockaddr_storage client_address;
-  socklen_t calen;
 
   set_program_name (argv[0]);
 
@@ -1049,7 +1096,22 @@ main (int argc, char **argv)
     gnutls_session_ticket_key_generate (&session_ticket_key);
 #endif
 
-  if (listen_socket (name, port) < 0)
+  if (info.udp)
+    return udp_server(name, info.port);
+  else
+    return tcp_server(name, info.port);
+}
+
+static int tcp_server(const char* name, int port)
+{
+  int n, s;
+  char topbuf[512];
+  int accept_fd;
+  struct sockaddr_storage client_address;
+  socklen_t calen;
+
+  s = listen_socket (name, port, SOCK_STREAM);
+  if (s < 0)
     exit (1);
 
   for (;;)
@@ -1112,7 +1174,7 @@ main (int argc, char **argv)
           {
             gnutls_session_t tls_session;
 
-            tls_session = initialize_session ();
+            tls_session = initialize_session (0);
 
             calen = sizeof (client_address);
             memset (&client_address, 0, calen);
@@ -1462,8 +1524,6 @@ gaa_parser (int argc, char **argv)
 
   dh_params_file = info.dh_params_file;
 
-  port = info.port;
-
   x509_certfile = info.x509_certfile;
   x509_keyfile = info.x509_keyfile;
   x509_dsacertfile = info.x509_dsacertfile;
diff --git a/src/serv.gaa b/src/serv.gaa
index 0d886a5..93cc85d 100644
--- a/src/serv.gaa
+++ b/src/serv.gaa
@@ -31,6 +31,9 @@ option (noticket) { $noticket = 1 } "Does not issue session 
tickets."
 option (http) { $http = 1 } "Act as an HTTP Server."
 option (echo) { $http = 0 } "Act as an Echo Server."
 
+#int udp;
+option (udp) { $udp = 1 } "Enable UDP server instead of TCP."
+
 #char *dh_params_file;
 option (dhparams) STR "FILE" { $dh_params_file = $1 } "DH params file to use."
 
@@ -103,4 +106,4 @@ init { $generate=0; $port=5556; $http=0; $nodb = 0; 
$noticket = 0;
        $pgp_keyring=NULL; $fmtder = 0;
        $disable_client_cert = 0; $priorities = NULL;
        $dh_params_file=NULL; $debug=0; $require_cert = 0; $psk_passwd = 0;
-       $pgp_subkey = NULL;}
+       $pgp_subkey = NULL; $udp = 0; }
diff --git a/src/udp-serv.c b/src/udp-serv.c
new file mode 100644
index 0000000..332917e
--- /dev/null
+++ b/src/udp-serv.c
@@ -0,0 +1,174 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include "udp-serv.h"
+#include "list.h"
+
+typedef struct {
+  gnutls_session_t session;
+  int fd;
+  struct sockaddr * cli_addr;
+  socklen_t cli_addr_size;
+} priv_data_st;
+
+static int pull_timeout_func(gnutls_transport_ptr ptr, void* data, size_t 
data_size, unsigned int ms);
+static ssize_t push_func (gnutls_transport_ptr_t p, const void * data, size_t 
size);
+static ssize_t pull_func(gnutls_transport_ptr_t p, void * data, size_t size);
+
+#define MAX_BUFFER 255     /* Longest string to echo */
+
+int udp_server(const char* name, int port)
+{
+    int sock, ret;
+    struct sockaddr_in cli_addr;
+    socklen_t cli_addr_size;
+    char buffer[MAX_BUFFER];
+    priv_data_st priv;
+    gnutls_session_t session;
+
+    ret = listen_socket (name, port, SOCK_DGRAM);
+    if (ret < 0)
+      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, 1, MSG_PEEK, (struct sockaddr*)&cli_addr, 
&cli_addr_size);
+        if (ret == 1)
+          printf ("Accepted connection from %s\n",
+                            human_addr ((struct sockaddr *)
+                                        &cli_addr, sizeof(cli_addr), buffer,
+                                        sizeof (buffer)));
+        else
+          continue;
+
+        session = initialize_session(1);
+
+        priv.session = session;
+        priv.fd = sock;
+        priv.cli_addr = (struct sockaddr *)&cli_addr;
+        priv.cli_addr_size = sizeof(cli_addr);
+
+        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);
+
+        ret = gnutls_handshake(session);
+        if (ret < 0)
+          {
+            fprintf(stderr, "Error in handshake(): %s\n", 
gnutls_strerror(ret));
+            continue;
+          }
+
+        for(;;)
+          {
+            ret = gnutls_record_recv(session, buffer, MAX_BUFFER);
+            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[%d]: %s\n", ret, buffer);
+
+            /* 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);
+}
+
+/* Wait for data to be received within a timeout period in milliseconds
+ */
+static int pull_timeout_func(gnutls_transport_ptr ptr, void* data, size_t 
data_size, unsigned int ms)
+{
+fd_set rfds;
+struct timeval tv;
+priv_data_st *priv = ptr;
+struct sockaddr_in cli_addr;
+socklen_t cli_addr_size;
+int ret;
+char c;
+
+  FD_ZERO(&rfds);
+  FD_SET(priv->fd, &rfds);
+  
+  tv.tv_sec = 0;
+  tv.tv_usec = ms * 1000;
+  
+  ret = select(priv->fd+1, &rfds, NULL, NULL, &tv);
+
+  if (ret <= 0)
+    return ret;
+
+  if (data_size == 0)
+    {
+      data = &c;
+      data_size = 1;
+    }
+
+  /* only report ok if the next message is from the peer we expect
+   * from 
+   */
+  cli_addr_size = sizeof(cli_addr);
+  ret = recvfrom(priv->fd, data, data_size, MSG_PEEK, (struct 
sockaddr*)&cli_addr, &cli_addr_size);
+  if (ret > 0)
+    {
+      if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, 
priv->cli_addr, sizeof(cli_addr))==0)
+        return 1;
+    }
+
+  return 0;
+}
+
+static ssize_t push_func (gnutls_transport_ptr_t p, const void * data, size_t 
size)
+{
+priv_data_st *priv = p;
+
+  return sendto(priv->fd, data, size, 0, priv->cli_addr, priv->cli_addr_size);
+}
+
+static ssize_t pull_func(gnutls_transport_ptr_t p, void * data, size_t size)
+{
+priv_data_st *priv = p;
+struct sockaddr_in cli_addr;
+socklen_t cli_addr_size;
+char buffer[64];
+int ret;
+
+  cli_addr_size = sizeof(cli_addr);
+  ret = recvfrom(priv->fd, data, size, 0, (struct sockaddr*)&cli_addr, 
&cli_addr_size);
+  if (ret == -1)
+    return ret;
+
+  if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, 
priv->cli_addr, sizeof(cli_addr))==0)
+    return ret;
+
+  printf ("Denied connection from %s\n",
+                human_addr ((struct sockaddr *)
+                            &cli_addr, sizeof(cli_addr), buffer,
+                            sizeof (buffer)));
+  
+  gnutls_transport_set_errno(priv->session, EAGAIN);
+  return -1;
+}
diff --git a/src/udp-serv.h b/src/udp-serv.h
new file mode 100644
index 0000000..7a481b9
--- /dev/null
+++ b/src/udp-serv.h
@@ -0,0 +1,8 @@
+#include <gnutls/dtls.h>
+
+int udp_server(const char* name, int port);
+gnutls_session_t initialize_session (int dtls);
+const char * human_addr (const struct sockaddr *sa, socklen_t salen,
+            char *buf, size_t buflen);
+int wait_for_connection(void);
+int listen_socket (const char *name, int listen_port, int socktype);


hooks/post-receive
-- 
GNU gnutls



reply via email to

[Prev in Thread] Current Thread [Next in Thread]