]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Changes to allow DTLS server side to operate. Added a simple UDP server on gnutls...
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 19 Feb 2011 15:57:44 +0000 (16:57 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 19 Feb 2011 18:08:35 +0000 (19:08 +0100)
Server other cleanups.

21 files changed:
lib/Makefile.am
lib/ext_session_ticket.c
lib/gnutls_buffers.c
lib/gnutls_buffers.h
lib/gnutls_constate.c
lib/gnutls_dtls.c
lib/gnutls_handshake.c
lib/gnutls_int.h
lib/gnutls_state.c
lib/includes/gnutls/gnutls.h.in
lib/libgnutls.map
lib/system.c
lib/system.h
lib/system_override.c [new file with mode: 0644]
src/Makefile.am
src/serv-gaa.c
src/serv-gaa.h
src/serv.c
src/serv.gaa
src/udp-serv.c [new file with mode: 0644]
src/udp-serv.h [new file with mode: 0644]

index 6a2b1dce4695b75c68dcc2cb63634bdfd2825224..edf520918217eb3d7837ee4bb72557e84eccf7e9 100644 (file)
@@ -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
index 9c44b90555091352d3f4014bf5e8fe1d9abcd655..f51c127e7b2611c64c0779608e53cf4c3de33089 100644 (file)
@@ -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
index a57784f63320b300a0d6700adcb49f0991e5604f..41b024488f8531a70f1493f1a428e7b1efa1a921 100644 (file)
  */
 #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;
-}
index 8028f734ef01cb59a8043d8ad81d97eccfda9a6b..37371ba6fbb0e28164bca9087f1602cc66ba898b 100644 (file)
@@ -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
index aadb110d6656c7cf0be8a4c4d3a8dc968cab14da..9e25d32fdef7ebeeaef11fece589054265e01e31 100644 (file)
@@ -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
index 81d3e5f88f3c0f0eb3a0b700602b1e95ad36d5a7..fdb8479347d117f221ac1a622b95cabeed7bc0f9 100644 (file)
@@ -57,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;
 
@@ -70,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;
@@ -93,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);
@@ -119,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)
@@ -153,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.
  *
@@ -170,26 +190,47 @@ int ret;
   /* PREPARING -> SENDING state transition */
   dtls_hsk_retransmit_buffer *msg;
   unsigned int total_timeout = 0;
+  gnutls_handshake_description_t last_type = 0;
 
   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);
+        {
+          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_check_recv(session, session->internals.dtls.retrans_timeout);
-      total_timeout += session->internals.dtls.retrans_timeout;
+      /* 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);
 
   if (ret < 0)
@@ -202,6 +243,7 @@ int ret;
   ret = 0;
 
 cleanup:
+  drop_usage_count(session);
   _gnutls_dtls_clear_outgoing_buffer (session);
 
   /* SENDING -> WAITING state transition */
index 9889c3bd513002826a6a6da3e9e6945c91e3ea1e..454232b26f00cad7d65698ea501372be5ae4d054 100644 (file)
@@ -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 =
index 0923bbc0ba3e1614a00b72e311e0694512344d9f..d3da01d6efcae4af20077621fbd355010ac1a5eb 100644 (file)
@@ -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
@@ -703,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;
index 0ceaa2d74ea354fe441c40c2fdbfc6b94c3e3df6..ab2350e2cd99262ebdd9881fb3a53fc6b5eaf967 100644 (file)
@@ -372,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;
 }
@@ -407,8 +408,8 @@ 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 = 100;
-  (*session)->internals.dtls.total_timeout = 3000;
+  (*session)->internals.dtls.retrans_timeout = 1000;
+  (*session)->internals.dtls.total_timeout = 4000;
 
   return 0;
 }
index 93b1cea44eafe21868c47b0a20736209d633396d..ebe09bd63f15b97a7ef0230a6520d04fb31b6052 100644 (file)
@@ -1184,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);
 
@@ -1210,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);
 
index fa16a998efd0c0942d02f261e4bf495d379168f4..5576c5a953d1bf6661a2f25a6f2c1a82e2b0d772 100644 (file)
@@ -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;
@@ -698,7 +700,8 @@ GNUTLS_2_12
        gnutls_cipher_tag;
        gnutls_cipher_add_auth;
        gnutls_dtls_set_timeouts;
-} GNUTLS_2_10;
+       gnutls_transport_set_pull_timeout_function;
+} GNUTLS_2_12;
 
 GNUTLS_PRIVATE {
   global:
index d89c283709afe0590d1b45c38564c6428fa406ce..169dd1551c9431bec466d519bd777eadc9fb0c27 100644 (file)
@@ -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 */
index 6ec4e8320435ea3e183f62f51bc6cba6f0eac2a9..207e6fa49d4ea8c509de4ea044ea393957dd5dc0 100644 (file)
@@ -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 (file)
index 0000000..852ec2b
--- /dev/null
@@ -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;
+}
index 509a446b0d75410165384417e270e0150ad35a1a..622ee8c2ed6d1cf96b83ba1a8693f1102b21648b 100644 (file)
@@ -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)
index a3c050d50ba801a43b00a4785df203afa355a721..e1fd2ece1532ea30c73c947fa6fa10bcb49ccdac 100644 (file)
@@ -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,9 +948,16 @@ 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:
@@ -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;
index 2a4a08ab439a79b5b5351e7979a2186d288a996c..0a1d560866ac5df1d36b2021823439dadc72fff3 100644 (file)
@@ -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"
index 068762438ddd4b605b2e8bf246404e2306cecdc5..698ab5019d38f9c4b6bc76e13b8b78a5b6839cbc 100644 (file)
@@ -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;
index 0d886a54c008798437a6133df994f9d4ed99ccbc..93cc85d98ebc59008b83b6242bffa0f308c61580 100644 (file)
@@ -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 (file)
index 0000000..332917e
--- /dev/null
@@ -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 (file)
index 0000000..7a481b9
--- /dev/null
@@ -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);