updates.
authorPekka Riikonen <priikone@silcnet.org>
Thu, 29 Nov 2001 19:07:44 +0000 (19:07 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 29 Nov 2001 19:07:44 +0000 (19:07 +0000)
14 files changed:
CHANGES
TODO
acconfig.h.pre
apps/silcd/server.c
apps/silcd/serverid.c
apps/silcd/serverid.h
configure.in.pre
includes/silcincludes.h
lib/silcutil/silcnet.c
lib/silcutil/silcnet.h
lib/silcutil/silcsockconn.c
lib/silcutil/silcutil.c
lib/silcutil/unix/silcunixthread.c
lib/silcutil/win32/silcwin32thread.c

diff --git a/CHANGES b/CHANGES
index 84a339e212bd362e3c098d9b00ea073e06a127e1..84e615f0b08832a96adc14e8de88ce1539f1007e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,23 @@
+Thu Nov 29 19:31:23 EET 2001  Pekka Riikonen <priikone@silcnet.org>'
+
+       * Added IPv6 support checking to the configure.in.pre, added
+         also --enable-ipv6 option to override the check.  Affected
+         file configure.in.pre.
+
+       * The silc_thread_create now calls the start function
+         directly if threads support is not compiled in.  Removes
+         ugly #ifdef's from generic code.  Affected files are
+         lib/silcutil/unix/silcunixthread, win32/silcwin32thread.c.
+
+       * Added silc_net_gethostby[name/addr]_async to asynchronously
+         resolve.  Affected files are lib/silcutil/silcnet.[ch].
+
+       * Added support for rendering IPv6 based server, client and
+         channel IDs.  Affected file lib/silcutil/silcutil.c.
+
+       * Added support for creating IPv6 based server IDs.  Affected
+         file is silcd/serverid.c.
+
 Wed Nov 28 23:46:09 EET 2001  Pekka Riikonen <priikone@silcnet.org>'
 
        * Added silc_net_gethostby[addr/name] into the
diff --git a/TODO b/TODO
index eb752293cf5555005046081d1e4c7cbc817c4718..3149ab185b386944fbd92326ac96a6ddb140684f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -87,10 +87,6 @@ TODO/bugs In SILC Server
    If it is, there is no reason to send it to the router, since the server
    knows it best.
 
- o Incomplete IPv6 support:
-
-       o silcd/serverid.c and its routines supports only IPv4.
-
  o New configuration file format must be added.  The new one will be
    done using the dotconf config library (lib/dotconf).  The following
    tasks relates closely to this as well and must be done at the same time
@@ -114,15 +110,7 @@ TODO/bugs In SILC Server
 TODO/bugs In SILC Libraries
 ===========================
 
- o Incomplete IPv6 support:
-
-       o All network routines in lib/silcutil/silcnet.[ch] does not
-         support IPv6.
-       o silc_id_render supports only IPv4 based ID's in the file
-         lib/silcutil/silcutil.c.
-
- o Add silc_net_gethostbyname, silc_net_gethostbyaddr,
-   silc_net_gethostbyname_async and silc_net_gethostbyaddr_async functions.
+ o See client library TODO/bugs
 
 
 TODO/Bugs in native WIN32 support (libraries)
index a1649da8425858692513eb33a48df63b95c9a959..d8a1fccafa86389d77c56c1deaab9b06cb77c565 100644 (file)
@@ -17,6 +17,9 @@
 #undef SILC_THREADS
 #undef SILC_HAVE_PTHREAD
 
+/* IPv6 support */
+#undef HAVE_IPV6
+
 /* Default paths */
 #undef SILC_ETCDIR
 #undef SILC_HELPDIR
index 4543cc28cabe994c8d984903fed396cbfa01e4fa..c831c1586bcede4b0cbd29d08c0e300e8054fa98 100644 (file)
@@ -222,11 +222,32 @@ int silc_server_init(SilcServer server)
     silc_net_set_socket_nonblock(sock[i]);
     server->sock = sock[i];
     
+    /* Add ourselves also to the socket table. The entry allocated above
+       is sent as argument for fast referencing in the future. */
+    silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+    server->sockets[sock[i]] = newsocket;
+    
+    /* Perform name and address lookups to resolve the listenning address
+       and port. */
+    if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname, 
+                                     &newsocket->ip)) {
+      if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
+         !newsocket->ip) {
+       SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
+                       newsocket->hostname ? newsocket->hostname :
+                       newsocket->ip ? newsocket->ip : ""));
+       server->stat.conn_failures++;
+       goto err0;
+      }
+      if (!newsocket->hostname)
+       newsocket->hostname = strdup(newsocket->ip);
+    }
+    newsocket->port = silc_net_get_local_port(sock[i]);
+
     /* Create a Server ID for the server. */
-    silc_id_create_server_id(sock[i], server->rng, &id);
-    if (!id) {
+    silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
+    if (!id)
       goto err0;
-    }
     
     server->id = id;
     server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
@@ -248,33 +269,10 @@ int silc_server_init(SilcServer server)
     }
     id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
     
-    /* Add ourselves also to the socket table. The entry allocated above
-       is sent as argument for fast referencing in the future. */
-    silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, id_entry, 
-                     &newsocket);
-
-    server->sockets[sock[i]] = newsocket;
-    
-    /* Perform name and address lookups to resolve the listenning address
-       and port. */
-    if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname, 
-                                    &newsocket->ip)) {
-      if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
-         !newsocket->ip) {
-       SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
-                       newsocket->hostname ? newsocket->hostname :
-                       newsocket->ip ? newsocket->ip : ""));
-       server->stat.conn_failures++;
-       goto err0;
-      }
-      if (!newsocket->hostname)
-       newsocket->hostname = strdup(newsocket->ip);
-    }
-    newsocket->port = silc_net_get_local_port(sock[i]);
-
     /* Put the allocated socket pointer also to the entry allocated above 
        for fast back-referencing to the socket list. */
-    id_entry->connection = (void *)server->sockets[sock[i]];
+    newsocket->user_data = (void *)id_entry;
+    id_entry->connection = (void *)newsocket;
     server->id_entry = id_entry;
   }
 
index 2d153f32f229f0b2b72144669cd0ed2aaf5e7c06..05cf1b35757d845041819ac146d5a2e0b7b29628 100644 (file)
 /* Creates a Server ID. Newly created Server ID is returned to the
    new_id argument. */
 
-void silc_id_create_server_id(int sock, SilcRng rng, SilcServerID **new_id)
+void silc_id_create_server_id(const char *ip, uint16 port, SilcRng rng, 
+                             SilcServerID **new_id)
 {
-  struct sockaddr_in server;
-  int rval, len;
-
   SILC_LOG_DEBUG(("Creating new Server ID"));
 
   *new_id = silc_calloc(1, sizeof(**new_id));
 
-  /* Get IP address */
-  len = sizeof(server);
-  rval = getsockname(sock, (struct sockaddr *)&server, &len);
-  if (rval < 0) {
-    SILC_LOG_ERROR(("Could not get IP address: %s", strerror(errno)));
+  /* Create the ID */
+
+  if (!silc_net_addr2bin(ip, (*new_id)->ip.data, 
+                        sizeof((*new_id)->ip.data))) {
     silc_free(*new_id);
     *new_id = NULL;
     return;
   }
 
-  /* Create the ID */
-  /* XXX Does not support IPv6 */
-  memcpy((*new_id)->ip.data, &server.sin_addr.s_addr, 4);
-  (*new_id)->ip.data_len = 4;
-  (*new_id)->port = server.sin_port;
+  (*new_id)->ip.data_len = silc_net_is_ip4(ip) ? 4 : 16;
+  (*new_id)->port = htons(port);
   (*new_id)->rnd = silc_rng_get_rn16(rng);
 
   SILC_LOG_DEBUG(("New ID (%s)", silc_id_render(*new_id, SILC_ID_SERVER)));
index 4a81a4a44e83273c0f39cc91a3e8f78b42edf45e..9873ec2d67fcec8bde8d70e2ffdd0ca4110efc65 100644 (file)
@@ -22,7 +22,8 @@
 #define SERVERID_H
 
 /* Prototypes */
-void silc_id_create_server_id(int sock, SilcRng rng, SilcServerID **new_id);
+void silc_id_create_server_id(const char *ip, uint16 port, SilcRng rng, 
+                             SilcServerID **new_id);
 bool silc_id_create_client_id(SilcServer server,
                              SilcServerID *server_id, SilcRng rng,
                              SilcHash md5hash, char *nickname, 
index 82762d4420d9b9d7c51a6aea4608087c61f6bf84..d7722afa39c23d2f0ec7f21f2b74757b8a6561e0 100644 (file)
@@ -611,12 +611,49 @@ AC_ARG_WITH(win32,
 
 AM_CONDITIONAL(SILC_WIN32, test x$win32-support = xtrue)
 
+#
+# IPv6 support
+#
+AC_MSG_CHECKING(for IPv6 support)
+AC_ARG_ENABLE(ipv6,
+[  --enable-ipv6           Enable IPv6 support],
+[ case "${enableval}" in
+  yes) 
+    want_ipv6=true
+    check_ipv6=false
+    AC_DEFINE(HAVE_IPV6)
+    AC_MSG_RESULT(yes)
+    ;;
+  *)
+    want_ipv6=false
+    check_ipv6=false
+    AC_MSG_RESULT(no)
+    ;;
+esac ], check_ipv6=true)
+
+if test x$check_ipv6 = xtrue; then
+  AC_TRY_COMPILE([#ifdef HAVE_NETINET_TCP_H
+                 #include <netinet/tcp.h>
+                 #endif
+                 #ifdef HAVE_NETDB_H
+                 #include <netdb.h>
+                 #endif
+                 #include <sys/socket.h>
+                 #ifdef HAVE_NETDB_IN_H
+                 #include <netinet/in.h>
+                 #endif],
+                 [struct sockaddr_in6 sin6;
+                  int family = AF_INET6;
+                 ], [AC_DEFINE(HAVE_IPV6)
+                     AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)])
+fi
+
 #
 # Debug checking
 #
 AC_MSG_CHECKING(for enabled debugging)
 AC_ARG_ENABLE(debug,
-[  --enable-debug          Enable debugging (warning: it is heavy!)],
+[  --enable-debug          Enable debugging],
 [ case "${enableval}" in
   yes) 
     AC_MSG_RESULT(yes)
index 7ee3c0d03cb8b67af3be2b981f403c8b59440f75..9117082c4a2525cb0438f0e75c1cf90e4d217dca 100644 (file)
@@ -233,6 +233,7 @@ typedef uint32 * void *;
 /* SILC util library includes */
 #include "silcmutex.h"
 #include "silcthread.h"
+#include "silcschedule.h"
 #include "silchashtable.h"
 #include "silclog.h"
 #include "silcmemory.h"
@@ -242,7 +243,6 @@ typedef uint32 * void *;
 #include "silcnet.h"
 #include "silcutil.h"
 #include "silcconfig.h"
-#include "silcschedule.h"
 #include "silcprotocol.h"
 #include "silcsockconn.h"
 
index f7795865ccf85f454153bb5202072c24b2277723..272e7e300f306738495159bad4af86abf1f3a0e4 100644 (file)
@@ -87,6 +87,60 @@ bool silc_net_is_ip(const char *addr)
   return silc_net_is_ip6(addr);
 }
 
+/* Internal context for async resolving */
+typedef struct {
+  SilcNetResolveCallback completion;
+  void *context;
+  SilcSchedule schedule;
+  char *input;
+  char *result;
+} *SilcNetResolveContext;
+
+SILC_TASK_CALLBACK(silc_net_resolve_completion)
+{
+  SilcNetResolveContext r = (SilcNetResolveContext)context;
+
+  /* Call the completion callback */
+  if (r->completion)
+    (*r->completion)(r->result, r->context);
+
+  silc_free(r->input);
+  silc_free(r->result);
+  silc_free(r);
+}
+
+/* Thread function to resolve the address for hostname. */
+
+static void *silc_net_gethostbyname_thread(void *context)
+{
+  SilcNetResolveContext r = (SilcNetResolveContext)context;
+  char tmp[64];
+
+  if (silc_net_gethostbyname(r->input, tmp, sizeof(tmp)))
+    r->result = strdup(tmp);
+
+  silc_schedule_task_add(r->schedule, 0, silc_net_resolve_completion, r, 0, 1,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_wakeup(r->schedule);
+  return NULL;
+}
+
+/* Thread function to resolve the hostname for address. */
+
+static void *silc_net_gethostbyaddr_thread(void *context)
+{
+  SilcNetResolveContext r = (SilcNetResolveContext)context;
+  char tmp[256];
+
+  if (silc_net_gethostbyaddr(r->input, tmp, sizeof(tmp)))
+    r->result = strdup(tmp);
+
+  silc_schedule_task_add(r->schedule, 0, silc_net_resolve_completion, r, 0, 1,
+                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  silc_schedule_wakeup(r->schedule);
+  return NULL;
+}
+
 /* Resolves IP address for hostname. */
 
 bool silc_net_gethostbyname(const char *name, char *address,
@@ -131,6 +185,23 @@ bool silc_net_gethostbyname(const char *name, char *address,
   return TRUE;
 }
 
+/* Resolves IP address for hostname async. */
+
+void silc_net_gethostbyname_async(const char *name, 
+                                 SilcSchedule schedule,
+                                 SilcNetResolveCallback completion,
+                                 void *context)
+{
+  SilcNetResolveContext r = silc_calloc(1, sizeof(*r));
+
+  r->completion = completion;
+  r->context = context;
+  r->schedule = schedule;
+  r->input = strdup(name);
+
+  silc_thread_create(silc_net_gethostbyname_thread, r, FALSE);
+}
+
 /* Resolves hostname by IP address. */
 
 bool silc_net_gethostbyaddr(const char *addr, char *name, uint32 name_len)
@@ -165,6 +236,23 @@ bool silc_net_gethostbyaddr(const char *addr, char *name, uint32 name_len)
   return TRUE;
 }
 
+/* Resolves hostname by IP address async. */
+
+void silc_net_gethostbyaddr_async(const char *addr, 
+                                 SilcSchedule schedule,
+                                 SilcNetResolveCallback completion,
+                                 void *context)
+{
+  SilcNetResolveContext r = silc_calloc(1, sizeof(*r));
+
+  r->completion = completion;
+  r->context = context;
+  r->schedule = schedule;
+  r->input = strdup(addr);
+
+  silc_thread_create(silc_net_gethostbyaddr_thread, r, FALSE);
+}
+
 /* Performs lookups for remote name and IP address. This peforms reverse
    lookup as well to verify that the IP has FQDN. */
 
index 69f49221869017e2e767da5ed8f92627a26091f8..7089acb22a68215fb9ea670963e29e37f4745c1b 100644 (file)
@@ -232,6 +232,22 @@ bool silc_net_is_ip(const char *addr);
  ***/
 bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len);
 
+/****f* silcutil/SilcNetAPI/SilcNetResolveCallback
+ *
+ * SYNOPSIS
+ *
+ *    typedef void (*SilcNetResolveCallback)(const char *result, 
+ *                                           void *context);
+ *
+ * DESCRIPTION
+ *
+ *    A callback function of this type is called after the asynchronous
+ *    resolving operation has been completed.  This callback is used
+ *    when asynchronously resolving IP addresses and hostnames.
+ *
+ ***/
+typedef void (*SilcNetResolveCallback)(const char *result, void *context);
+
 /****f* silcutil/SilcNetAPI/silc_net_gethostbyname
  *
  * SYNOPSIS
@@ -241,7 +257,7 @@ bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len);
  *
  * DESCRIPTION
  *
- *    Resolves the IP address of the hostname indicated by the `host'
+ *    Resolves the IP address of the hostname indicated by the `host'.
  *    This returns TRUE and the IP address of the host, or FALSE
  *    if the address could not be resolved.  This is synchronous
  *    function and will block the calling process.
@@ -250,6 +266,28 @@ bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len);
 bool silc_net_gethostbyname(const char *name, char *address, 
                            uint32 address_len);
 
+/****f* silcutil/SilcNetAPI/silc_net_gethostbyname_async
+ *
+ * SYNOPSIS
+ *
+ *    void silc_net_gethostbyname_async(const char *name, 
+ *                                      SilcSchedule schedule,
+ *                                      SilcNetResolveCallback completion,
+ *                                      void *context)
+ *
+ * DESCRIPTION
+ *
+ *    Asynchronouosly resolves the IP address of the hostname indicated
+ *    by the `host'.  This function returns immediately, and the
+ *    `completion' callback will be called after the resolving is
+ *    completed.
+ *
+ ***/
+void silc_net_gethostbyname_async(const char *name, 
+                                 SilcSchedule schedule,
+                                 SilcNetResolveCallback completion,
+                                 void *context);
+
 /****f* silcutil/SilcNetAPI/silc_net_gethostbyaddr
  *
  * SYNOPSIS
@@ -259,7 +297,7 @@ bool silc_net_gethostbyname(const char *name, char *address,
  *
  * DESCRIPTION
  *
- *    Resolves the hostname of the IP address indicated by the `addr'
+ *    Resolves the hostname for the IP address indicated by the `addr'
  *    This returns TRUE and the resolved hostname, or FALSE on error.
  *    The `addr' may be either IPv4 or IPv6 address.  This is
  *    synchronous function and will block the calling process.
@@ -267,6 +305,28 @@ bool silc_net_gethostbyname(const char *name, char *address,
  ***/
 bool silc_net_gethostbyaddr(const char *addr, char *name, uint32 name_len);
 
+/****f* silcutil/SilcNetAPI/silc_net_gethostbyaddr_async
+ *
+ * SYNOPSIS
+ *
+ *    void silc_net_gethostbyaddr_async(const char *addr, 
+ *                                      SilcSchedule schedule,
+ *                                      SilcNetResolveCallback completion,
+ *                                      void *context)
+ *
+ * DESCRIPTION
+ *
+ *    Asynchronouosly resolves the hostname for the IP address indicated
+ *    by the `addr'.  This function returns immediately, and the
+ *    `completion' callback will be called after the resolving is
+ *    completed.
+ *
+ ***/
+void silc_net_gethostbyaddr_async(const char *addr, 
+                                 SilcSchedule schedule,
+                                 SilcNetResolveCallback completion,
+                                 void *context);
+
 /****f* silcutil/SilcNetAPI/silc_net_check_host_by_sock
  *
  * SYNOPSIS
index 942b30d8664e37ef46b36fd9762d39ccce7219da..d722cd0d8819f6eb7fa7d4e6d0ec7fddc3d2ed43 100644 (file)
@@ -224,10 +224,5 @@ void silc_socket_host_lookup(SilcSocketConnection sock,
   lookup->port = port_lookup;
 
   SILC_SET_HOST_LOOKUP(sock);
-
-#ifdef SILC_THREADS
   silc_thread_create(silc_socket_host_lookup_start, lookup, FALSE);
-#else
-  silc_socket_host_lookup_start((void *)lookup);
-#endif
 }
index c37ec4e55df810e5c16206f1b94e3254016cc384..15ad5eab37ccf053d4f1e08e17729251f5bc89a7 100644 (file)
@@ -539,12 +539,16 @@ char *silc_id_render(void *id, uint16 type)
   case SILC_ID_SERVER:
     {
       SilcServerID *server_id = (SilcServerID *)id;
-      struct in_addr ipv4;
-
       if (server_id->ip.data_len > 4) {
-
+#ifdef HAVE_IPV6
+       struct in6_addr ipv6;
+       memmove(&ipv6, server_id->ip.data, sizeof(ipv6));
+       if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
+         strcat(rid, tmp);
+#endif
       } else {
-       memcpy(&ipv4.s_addr, server_id->ip.data, 4);
+       struct in_addr ipv4;
+       memmove(&ipv4.s_addr, server_id->ip.data, 4);
        strcat(rid, inet_ntoa(ipv4));
       }
 
@@ -560,12 +564,16 @@ char *silc_id_render(void *id, uint16 type)
   case SILC_ID_CLIENT:
     {
       SilcClientID *client_id = (SilcClientID *)id;
-      struct in_addr ipv4;
-
       if (client_id->ip.data_len > 4) {
-
+#ifdef HAVE_IPV6
+       struct in6_addr ipv6;
+       memmove(&ipv6, client_id->ip.data, sizeof(ipv6));
+       if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
+         strcat(rid, tmp);
+#endif
       } else {
-       memcpy(&ipv4.s_addr, client_id->ip.data, 4);
+       struct in_addr ipv4;
+       memmove(&ipv4.s_addr, client_id->ip.data, 4);
        strcat(rid, inet_ntoa(ipv4));
       }
 
@@ -582,12 +590,16 @@ char *silc_id_render(void *id, uint16 type)
   case SILC_ID_CHANNEL:
     {
       SilcChannelID *channel_id = (SilcChannelID *)id;
-      struct in_addr ipv4;
-
       if (channel_id->ip.data_len > 4) {
-
+#ifdef HAVE_IPV6
+       struct in6_addr ipv6;
+       memmove(&ipv6, channel_id->ip.data, sizeof(ipv6));
+       if (!inet_ntop(AF_INET6, &ipv6, tmp, sizeof(tmp)))
+         strcat(rid, tmp);
+#endif
       } else {
-       memcpy(&ipv4.s_addr, channel_id->ip.data, 4);
+       struct in_addr ipv4;
+       memmove(&ipv4.s_addr, channel_id->ip.data, 4);
        strcat(rid, inet_ntoa(ipv4));
       }
 
index 7751603f61d68c11bbe62cbaa24253565f77015f..575c54a894a8b8d4f09210b11d8c0ed9cc0d0df9 100644 (file)
 
 #include "silcincludes.h"
 
-#ifdef SILC_THREADS
-
 SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
                              bool waitable)
 {
+#ifdef SILC_THREADS
   pthread_attr_t attr;
   pthread_t thread;
   int ret;
@@ -61,25 +60,38 @@ SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
   SILC_LOG_DEBUG(("Created thread %p", (SilcThread)thread));
 
   return (SilcThread)thread;
+#else
+  /* Call thread callback immediately */
+  (*start_func)(context);
+  return NULL;
+#endif
 }
 
 void silc_thread_exit(void *exit_value)
 {
+#ifdef SILC_THREADS
   pthread_exit(exit_value);
+#endif
 }
 
 SilcThread silc_thread_self(void)
 {
+#ifdef SILC_THREADS
   pthread_t self = pthread_self();
   return (SilcThread)self;
+#else
+  return NULL;
+#endif
 }
 
 bool silc_thread_wait(SilcThread thread, void **exit_value)
 {
+#ifdef SILC_THREADS
   SILC_LOG_DEBUG(("Waiting for thread %p", thread));
   if (!pthread_join(*(pthread_t *)thread, exit_value))
     return TRUE;
   return FALSE;
+#else
+  return FALSE;
+#endif
 }
-
-#endif /* SILC_THREADS */
index e88a09f0c4690bbfdf9f7cddad507ef43d6d79cb..6e6a90949521ab204206cdc7cd3a2a184f266fc1 100644 (file)
@@ -49,10 +49,12 @@ unsigned __stdcall silc_thread_win32_start(void *context)
 
   return 0;
 }
+#endif
 
 SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
                              bool waitable)
 {
+#ifdef SILC_THREADS
   SilcWin32Thread thread;
   unsigned id;
 
@@ -71,10 +73,16 @@ SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
   }
 
   return (SilcThread)thread;
+#else
+  /* Call thread callback immediately */
+  (*start_func)(context);
+  return NULL;
+#endif
 }
 
 void silc_thread_exit(void *exit_value)
 {
+#ifdef SILC_THREADS
   SilcWin32Thread thread = TlsGetValue(silc_thread_tls);
   
   if (thread) {
@@ -89,10 +97,12 @@ void silc_thread_exit(void *exit_value)
   }
 
   _endthreadex(0);
+#endif
 }
 
 SilcThread silc_thread_self(void)
 {
+#ifdef SILC_THREADS
   SilcWin32Thread self = TlsGetValue(silc_thread_tls);
 
   if (!self) {
@@ -107,10 +117,14 @@ SilcThread silc_thread_self(void)
   }
 
   return (SilcThread)self;
+#else
+  return NULL;
+#endif
 }
 
 bool silc_thread_wait(SilcThread thread, void **exit_value)
 {
+#ifdef SILC_THREADS
   SilcWin32Thread self = (SilcWin32Thread)thread;
 
   SILC_LOG_DEBUG(("Waiting for thread %p", self));
@@ -127,6 +141,7 @@ bool silc_thread_wait(SilcThread thread, void **exit_value)
     *exit_value = NULL;
 
   return TRUE;
+#else
+  return FALSE;
+#endif
 }
-
-#endif /* SILC_THREADS */