Added SILC Server library.
authorPekka Riikonen <priikone@silcnet.org>
Wed, 28 Dec 2005 14:19:05 +0000 (14:19 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 28 Dec 2005 14:19:05 +0000 (14:19 +0000)
Added SILC Key Repository library
silcincludes.h -> silc.h

206 files changed:
CHANGES
TODO
configure.ad
distdir/common
distdir/default
distdir/server
distdir/toolkit
includes/Makefile.ad
includes/silc.h.in [moved from includes/silcincludes.h.in with 97% similarity]
lib/Makefile.ad
lib/configure.ad
lib/contrib/getopti.c
lib/contrib/regexpr.c
lib/contrib/stringprep.h
lib/doc/silcclient_using.html
lib/silcasn1/silcasn1.c
lib/silcasn1/silcasn1_decode.c
lib/silcasn1/silcasn1_encode.c
lib/silcasn1/silcber.c
lib/silcasn1/tests/test_silcasn1.c
lib/silcclient/client.c
lib/silcclient/client_attrs.c
lib/silcclient/client_channel.c
lib/silcclient/client_ftp.c
lib/silcclient/client_keyagr.c
lib/silcclient/client_notify.c
lib/silcclient/client_prvmsg.c
lib/silcclient/client_resume.c
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silcclient/idlist.c
lib/silcclient/protocol.c
lib/silcclient/silcclient.h
lib/silccore/silcargument.c
lib/silccore/silcattrs.c
lib/silccore/silcattrs.h
lib/silccore/silcauth.c
lib/silccore/silcauth.h
lib/silccore/silcchannel.c
lib/silccore/silcchannel.h
lib/silccore/silccommand.c
lib/silccore/silccommand.h
lib/silccore/silcid.c
lib/silccore/silcid.h
lib/silccore/silcidcache.c
lib/silccore/silcidcache.h
lib/silccore/silcmessage.c
lib/silccore/silcmessage.h
lib/silccore/silcmode.h
lib/silccore/silcnotify.c
lib/silccore/silcpacket.c
lib/silccore/silcpacket.h
lib/silccore/silcstatus.c
lib/silccore/tests/test_silcargument.c
lib/silccrypt/aes.c
lib/silccrypt/blowfish.c
lib/silccrypt/cast.c
lib/silccrypt/md5.c
lib/silccrypt/none.c
lib/silccrypt/rc5.c
lib/silccrypt/rsa.c
lib/silccrypt/sha1.c
lib/silccrypt/sha256.c
lib/silccrypt/silccipher.c
lib/silccrypt/silccipher.h
lib/silccrypt/silchash.c
lib/silccrypt/silchmac.c
lib/silccrypt/silcpkcs.c
lib/silccrypt/silcpkcs.h
lib/silccrypt/silcpkcs1.c
lib/silccrypt/silcrng.c
lib/silccrypt/tests/test_aes.c
lib/silccrypt/tests/test_hmacmd5.c
lib/silccrypt/tests/test_hmacsha1.c
lib/silccrypt/tests/test_hmacsha256.c
lib/silccrypt/tests/test_md5.c
lib/silccrypt/tests/test_sha1.c
lib/silccrypt/tests/test_sha256.c
lib/silccrypt/tests/test_silcpkcs.c
lib/silccrypt/tests/test_twofish.c
lib/silccrypt/twofish.c
lib/silcmath/modinv.c
lib/silcmath/mp_gmp.c
lib/silcmath/mp_tfm.c
lib/silcmath/mp_tma.c
lib/silcmath/mpbin.c
lib/silcmath/silcprimegen.c
lib/silcserver/DIRECTORY [new file with mode: 0644]
lib/silcserver/Makefile.ad [new file with mode: 0644]
lib/silcserver/server.c [new file with mode: 0644]
lib/silcserver/server_entry.c [new file with mode: 0644]
lib/silcserver/server_entry.h [new file with mode: 0644]
lib/silcserver/server_params.c [new file with mode: 0644]
lib/silcserver/server_send.c [new file with mode: 0644]
lib/silcserver/server_st_accept.c [new file with mode: 0644]
lib/silcserver/server_st_accept.h [new file with mode: 0644]
lib/silcserver/server_st_command.c [new file with mode: 0644]
lib/silcserver/server_st_command.h [new file with mode: 0644]
lib/silcserver/server_st_command_reply.c [new file with mode: 0644]
lib/silcserver/server_st_command_reply.h [new file with mode: 0644]
lib/silcserver/server_st_connect.c [new file with mode: 0644]
lib/silcserver/server_st_connect.h [new file with mode: 0644]
lib/silcserver/server_st_notify.c [new file with mode: 0644]
lib/silcserver/server_st_notify.h [new file with mode: 0644]
lib/silcserver/server_st_packet.c [new file with mode: 0644]
lib/silcserver/server_st_packet.h [new file with mode: 0644]
lib/silcserver/server_st_query.c [new file with mode: 0644]
lib/silcserver/server_st_query.h [new file with mode: 0644]
lib/silcserver/silcserver.h [new file with mode: 0644]
lib/silcserver/silcserver_params.h [new file with mode: 0644]
lib/silcserver/tests/Makefile.am [new file with mode: 0644]
lib/silcserver/tests/test_silcserver.c [new file with mode: 0644]
lib/silcsftp/sftp_client.c
lib/silcsftp/sftp_fs_memory.c
lib/silcsftp/sftp_server.c
lib/silcsftp/sftp_util.c
lib/silcsftp/tests/sftp_client.c
lib/silcsftp/tests/sftp_server.c
lib/silcsim/silcsim.c
lib/silcsim/silcsimutil.c
lib/silcske/DIRECTORY
lib/silcske/Makefile.ad
lib/silcske/groups.c
lib/silcske/payload.c
lib/silcske/silcske.c
lib/silcske/silcske.h
lib/silcske/silcske_groups.h
lib/silcske/silcske_status.h [deleted file]
lib/silcskr/Makefile.ad [new file with mode: 0644]
lib/silcskr/silcskr.c [new file with mode: 0644]
lib/silcskr/silcskr.h [new file with mode: 0644]
lib/silcskr/silcskr_i.h [new file with mode: 0644]
lib/silcskr/tests/Makefile.am [new file with mode: 0644]
lib/silcskr/tests/test_silcskr.c [new file with mode: 0644]
lib/silcutil/beos/silcbeosmutex.c
lib/silcutil/beos/silcbeosnet.c
lib/silcutil/beos/silcbeossockconn.c
lib/silcutil/beos/silcbeosthread.c
lib/silcutil/beos/silcbeosutil.c
lib/silcutil/os2/silcos2mutex.c
lib/silcutil/os2/silcos2net.c
lib/silcutil/os2/silcos2schedule.c
lib/silcutil/os2/silcos2sockconn.c
lib/silcutil/os2/silcos2thread.c
lib/silcutil/os2/silcos2util.c
lib/silcutil/silcapputil.c
lib/silcutil/silcasync.c
lib/silcutil/silcasync.h
lib/silcutil/silcbuffmt.c
lib/silcutil/silcconfig.c
lib/silcutil/silcdlist.h
lib/silcutil/silcfdstream.c
lib/silcutil/silcfdstream.h
lib/silcutil/silcfileutil.c
lib/silcutil/silcfsm.c
lib/silcutil/silcfsm.h
lib/silcutil/silcfsm_i.h
lib/silcutil/silchashtable.c
lib/silcutil/silchashtable.h
lib/silcutil/silclist.h
lib/silcutil/silclog.c
lib/silcutil/silcmemory.c
lib/silcutil/silcmime.c
lib/silcutil/silcmime.h
lib/silcutil/silcmime_i.h [new file with mode: 0644]
lib/silcutil/silcnet.c
lib/silcutil/silcschedule.c
lib/silcutil/silcschedule.h
lib/silcutil/silcsocketstream.c
lib/silcutil/silcsocketstream.h
lib/silcutil/silcstack.c
lib/silcutil/silcstream.c
lib/silcutil/silcstream.h
lib/silcutil/silcstringprep.c
lib/silcutil/silcstrutil.c
lib/silcutil/silcstrutil.h
lib/silcutil/silctime.c
lib/silcutil/silctime.h
lib/silcutil/silcutf8.c
lib/silcutil/silcutil.c
lib/silcutil/silcutil.h
lib/silcutil/silcvcard.c
lib/silcutil/stacktrace.c
lib/silcutil/tests/test_silcasync.c
lib/silcutil/tests/test_silcfdstream.c
lib/silcutil/tests/test_silcfsm.c
lib/silcutil/tests/test_silchashtable.c
lib/silcutil/tests/test_silclist.c
lib/silcutil/tests/test_silcmime.c
lib/silcutil/tests/test_silcnet.c
lib/silcutil/tests/test_silcschedule.c
lib/silcutil/tests/test_silcstack.c
lib/silcutil/tests/test_silcstringprep.c
lib/silcutil/tests/test_silcstrutil.c
lib/silcutil/unix/silcunixmutex.c
lib/silcutil/unix/silcunixnet.c
lib/silcutil/unix/silcunixschedule.c
lib/silcutil/unix/silcunixsocketstream.c
lib/silcutil/unix/silcunixthread.c
lib/silcutil/unix/silcunixutil.c
lib/silcutil/win32/silcwin32mutex.c
lib/silcutil/win32/silcwin32net.c
lib/silcutil/win32/silcwin32schedule.c
lib/silcutil/win32/silcwin32sockconn.c
lib/silcutil/win32/silcwin32thread.c
lib/silcutil/win32/silcwin32util.c

diff --git a/CHANGES b/CHANGES
index 72b56db3422dc5ea5d2af2d26d52d214cafab64b..3fc948fd13338b45a1ac58302f8afb4d2364ac6b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,19 @@
+Wed Dec 28 13:55:22 EET 2005  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added SILC Key Repository library, lib/silcskr.
+
+       * Added SILC Server library, lib/silcserver.
+
+Mon Dec 19 18:04:24 EET 2005  Pekka Riikonen <priikone@silcnet.org>
+
+       * MIME objects in attributes now use SilcMime.  Affected files
+         are lib/silccore/silcattrs.[ch].
+
+Sat Dec 17 20:13:31 EET 2005  Pekka Riikonen <priikone@silcnet.org>
+
+       * Synchronize semaphore posting for real threads in FSM.
+         Affected files are lib/silcutil/silcfsm.c, silcfsm_i.h.
+
 Mon Nov 28 17:06:54 EET 2005  Pekka Riikonen <priikone@silcnet.org>
 
        * Added silc_file_set_nonblock.  Affected file is
diff --git a/TODO b/TODO
index 42161a4cb8f802978907a9c782d1b37b87f53acb..6e39a0ab897f3472f6ad2dc7489be16d79e90f0b 100644 (file)
--- a/TODO
+++ b/TODO
@@ -28,7 +28,7 @@ lib/silccrypt
  o ECDSA and ECDH.
 
 
-lib/silccore/silcpacket.[ch]   ****PARTLY DONE****
+lib/silccore/silcpacket.[ch]   ****DONE****
 ============================
 
  o SilcPacketEngine.
@@ -36,7 +36,13 @@ lib/silccore/silcpacket.[ch] ****PARTLY DONE****
  o New SILC Packet API.
 
 
-lib/silccore/silcid.[ch]
+lib/silccore/silcpacket.[ch]
+============================
+
+ o IV Included flag support, UDP transport support
+
+
+lib/silccore/silcid.[ch]       ****DONE****
 ========================
 
   o Add silc_id_str2id to accept the destination buffer as argument
@@ -46,7 +52,13 @@ lib/silccore/silcid.[ch]
   o silc_id_str2id, silc_id2str to non-allocating routines.
 
 
-lib/silcutil
+lib/silccore
+============
+
+  o All payload encoding routines should take SilcStack as argument.
+
+
+lib/silcutil                   ****PARTLY DONE****
 ============
 
  o Compression routines are missing.  The protocol supports packet
@@ -101,6 +113,8 @@ lib/silcutil/silcsocketstream.[ch]  ****PARTY DONE****
 
  o Add SilcSocketStream.
 
+ o Test QoS
+
 
 lib/silcutil/epoc/*
 ===================
@@ -205,25 +219,8 @@ lib/silcutil/silcnet*, lib/silcutil/*/silc*net*            ****PARTLY DONE****
    to handle the sockets by themself.
 
 
-apps/silcd
-==========
-
- o Remove the big switch statement from the function
-   silc_server_packet_parse_type and replace it with predefined
-   table of function pointers where each of the slot in table
-   represents the packet type value.
-
-   Same could be done with notify packets which has big switch
-   statement too.  Same kind of table of notify callbacks could be
-   done as well.
-
- o The parser callback in the server will add a timeout task for
-   all packets.  It will require registering and allocating a
-   new task to the SilcSchedule.  Maybe, at least, for server
-   and router packets the parser would be called immediately
-   instead of adding it to the scheduler with 0 timeout.  It
-   should be analyzed too how slow the task registering process
-   actually is, and find out ways to optimize it.
+lib/silcserver
+==============
 
  o The SERVER_SIGNOFF notify handing is not optimal, because it'll
    cause sending of multiple SIGNOFF notify's instead of the one
@@ -265,4 +262,10 @@ apps/silcd
    each JOIN command will create and distribute the new channel key
    to everybody on the channel (Fix this to 0.9.x).
 
+ o Related to above.  If multiple JOINs are received in sequence perhaps
+   new key should be created only once, if the JOINs are handeled at the same
+   time.  Now we create multiple keys and never end up using them because
+   many JOINs are processed at the same time in sequence.  Only the last
+   key ends up being used.
+
  o The CMODE cipher & hmac change problem (#101).
index 5d62cf4c5768ea65c1df51fb7c7cf1b661571717..f88c59c7ff5d9d1729d75a310aca42d0492fc582 100644 (file)
@@ -451,13 +451,13 @@ if test -n "$with_silc_includes" || test -n "$with_silc_libs"; then
   fi
 
   # Check libs to link against
-  f=`$EGREP __SILC_HAVE_PTHREAD $ac_silc_includes/silcincludes.h`
+  f=`$EGREP __SILC_HAVE_PTHREAD $ac_silc_includes/silc.h`
   if test -n "$f"; then
     LIBS="$LIBS -lpthread"
     check_threads=false
     has_threads=true
   fi
-  f=`$EGREP __SILC_HAVE_SIM $ac_silc_includes/silcincludes.h`
+  f=`$EGREP __SILC_HAVE_SIM $ac_silc_includes/silc.h`
   if test -n "$f"; then
     LIBS="$LIBS -ldl"
   fi
@@ -468,6 +468,9 @@ else
 #ifdef SILC_DIST_CLIENTLIB
   PKG_CHECK_MODULES(SILCCLIENT, silcclient, compile_libs=false, compile_libs=true)
 #endif SILC_DIST_CLIENTLIB
+#ifdef SILC_DIST_SERVERLIB
+  PKG_CHECK_MODULES(SILCSERVER, silcserver, compile_libs=false, compile_libs=true)
+#endif SILC_DIST_SERVERLIB
 
   if test x$compile_libs = xfalse; then
     LIBSUBDIR=
@@ -477,6 +480,10 @@ else
     LIBS="$LIBS $SILCCLIENT_LIBS"
     CFLAGS="$CFLAGS $SILCCLIENT_CFLAGS"
 #endif SILC_DIST_CLIENTLIB
+#ifdef SILC_DIST_SERVERLIB
+    LIBS="$LIBS $SILCSERVER_LIBS"
+    CFLAGS="$CFLAGS $SILCSERVER_CFLAGS"
+#endif SILC_DIST_SERVERLIB
   fi
 fi
 #endif SILC_DIST_TOOLKIT
@@ -1091,7 +1098,7 @@ Makefile.defines
 Makefile.defines_int
 includes/Makefile
 includes/silcversion.h
-includes/silcincludes.h
+includes/silc.h
 #endif SILC_DIST_COMPILER
 #ifdef SILC_DIST_APPS
 apps/Makefile
index effa387a972fd161270f349cc7338c1a1cf878fe..e1b34c8306c4e3ce5194ff7ba00ad799635943ac 100644 (file)
@@ -16,3 +16,6 @@ define SILC_DIST_TMA
 
 # ASN.1 library
 define SILC_DIST_ASN1
+
+# Key Repository library
+define SILC_DIST_SKR
index 9c3a9060884bb9a6417e5c83191872d5faefb3ba..4029c790117b7c59ce69d50f9aa01239ef725285 100644 (file)
@@ -9,7 +9,7 @@ option no-dist
 
 # Default distribution for preparing raw CVS sources.
 inherit common
-inherit client
+#inherit client
 inherit server
 inherit toolkit
 
index 97f82d34e955ca1e3a8674a994a36f4c22fe758a..b26937f980edd1fddb8a222b0613d0f273a37854 100644 (file)
@@ -4,6 +4,7 @@ bug-report silc-devel@lists.silcnet.org
 
 inherit common
 define SILC_DIST_SERVER
+define SILC_DIST_SERVERLIB
 undef SILC_DIST_SFTP
 
 post-process-dist-hook distdir/post-process-dist
index 3507909b11dadffd75fc1115af035601ace448c9..f40a1797ad009b8a8f289f36179094fca594e258 100644 (file)
@@ -4,7 +4,7 @@ bug-report silc-devel@lists.silcnet.org
 
 # Inherits
 inherit common
-inherit client
+#inherit client
 inherit server
 
 # License
index 9abf2d80d494e81242642d5c3e6e220cc09858ad..4a016351a1c8d637906159ab9e8d214d28c6008f 100644 (file)
@@ -19,7 +19,7 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 
 #ifdef SILC_DIST_TOOLKIT
 include_HEADERS = \
-       silcincludes.h \
+       silc.h \
        silcwin32.h \
        silcepoc.h \
        silcbeos.h \
@@ -28,7 +28,7 @@ include_HEADERS = \
 #endif SILC_DIST_TOOLKIT
 
 EXTRA_DIST = \
-       silcincludes.h \
+       silc.h \
        silcwin32.h \
        silcepoc.h \
        silcbeos.h \
similarity index 97%
rename from includes/silcincludes.h.in
rename to includes/silc.h.in
index 3442fe73de136a9e3c0ca98a29037fdab2d77e21..b85fd024aad5112307b936af7f16cebe7d2e32fd 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
-  silcincludes.h
+  silc.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
@@ -277,6 +277,7 @@ extern "C" {
 #include "silcfdstream.h"
 #include "silcvcard.h"
 #include "silcapputil.h"
+#include "silcmime.h"
 
 #ifdef SILC_DIST_ASN1
 #include "silcasn1.h"
@@ -297,6 +298,10 @@ extern "C" {
 #include "silcauth.h"
 #include "silcattrs.h"
 
+#ifdef SILC_DIST_SKR
+#include "silcskr.h"
+#endif /* SILC_DIST_SKR */
+
 #if defined(SILC_SIM)
 /* SILC Module library includes */
 #include "silcsim.h"
@@ -307,6 +312,7 @@ extern "C" {
 #include "silcske.h"
 #include "silcske_payload.h"
 #include "silcske_groups.h"
+#include "silcconnauth.h"
 
 #ifdef SILC_DIST_SFTP
 /* SILC SFTP library */
index 48fefd898daa3c18f64870c26d194aa55856e7f6..944bdc548397fc544adc970fdaeb760e43946012 100644 (file)
 
 AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 
+#ifdef SILC_DIST_SFTP
+#      silcsftp
 #endif SILC_DIST_SFTP
 
 # SILC Library dirs
-SILCLIB_DIRS = \
-       contrib \
-       silcutil \
-       silccrypt \
+SILCLIB_DIRS =                 \
+       contrib         \
+       silccore        \
+       silcutil        \
+       silccrypt       \
+#ifdef SILC_DIST_SKR
+       silcskr         \
+#endif SILC_DIST_SKR
 #ifdef SILC_DIST_MATH
-       silcmath \
+       silcmath        \
 #endif SILC_DIST_MATH
 #ifdef SILC_DIST_SIM
-       silcsim \
+       silcsim         \
+#endif SILC_DIST_SIM
 #ifdef SILC_DIST_ASN1
-       silcasn1 \
+       silcasn1        \
 #endif SILC_DIST_ASN1
-#endif SILC_DIST_SIM
-       silccore \
-       silcske \
-#ifdef SILC_DIST_SFTP
-       silcsftp
+       silcske
 
 SILCLIB = libsilc.a
 
@@ -46,22 +49,30 @@ SILCCLIENTLIB_DIRS = silcclient
 SILCCLIENTLIB = libsilcclient.a
 #endif SILC_DIST_CLIENTLIB
 
-SUBDIRS = $(SILCLIB_DIRS) #$(SILCCLIENTLIB_DIRS)
+#ifdef SILC_DIST_SERVERLIB
+# SILC Server Library dirs
+SILCSERVERLIB_DIRS = silcserver
+SILCSERVERLIB = libsilcserver.a
+#endif SILC_DIST_SERVERLIB
 
-CLEANFILES = libsilc.a libsilcclient.a
-DISTCLEANFILES = libsilc.a libsilcclient.a
+SUBDIRS = $(SILCLIB_DIRS) $(SILCSERVERLIB_DIRS) ###$(SILCCLIENTLIB_DIRS)
+
+CLEANFILES = libsilc.a libsilcclient.a libsilcserver.a
+DISTCLEANFILES = libsilc.a libsilcclient.a libsilcserver.a
 
 remove:
        -rm -f libsilc.a
        -rm -f libsilcclient.a
+       -rm -f libsilcserver.a
 
-all:   remove $(SILCLIB) #$(SILCCLIENTLIB)
+all:   remove $(SILCLIB) $(SILCSERVERLIB) ###$(SILCCLIENTLIB)
 
 #ifdef SILC_DIST_TOOLKIT
 install-exec-hook:
        -mkdir -p $(DESTDIR)$(libdir)
        -$(LIBTOOL) $(INSTALL) libsilc.la $(DESTDIR)$(libdir)/
        -$(LIBTOOL) $(INSTALL) libsilcclient.la $(DESTDIR)$(libdir)/
+       -$(LIBTOOL) $(INSTALL) libsilcserver.la $(DESTDIR)$(libdir)/
 #else !SILC_DIST_TOOLKIT
 
 #ifdef SILC_DIST_SERVER
@@ -69,7 +80,9 @@ install-exec-hook:
 if SILC_ENABLE_SHARED
        -mkdir -p $(libdir)
        -$(LIBTOOL) $(INSTALL) libsilc.la $(DESTDIR)$(libdir)/
+       -$(LIBTOOL) $(INSTALL) libsilcserver.la $(DESTDIR)$(libdir)/
        -rm -rf $(DESTDIR)$(libdir)/libsilc.a
+       -rm -rf $(DESTDIR)$(libdir)/libsilcserver.a
 endif
 #endif SILC_DIST_SERVER
 
@@ -108,11 +121,23 @@ libsilcclient.a:
        -release $(LIB_BASE_VERSION) -rpath $(DESTDIR)$(libdir) -o libsilcclient.la
 #endif SILC_DIST_CLIENTLIB
 
+#ifdef SILC_DIST_SERVERLIB
+LIBSILCSERVER_CURRENT=@LIBSILCSERVER_CURRENT@
+LIBSILCSERVER_REVISION=@LIBSILCSERVER_REVISION@
+LIBSILCSERVER_AGE=@LIBSILCSERVER_AGE@
+
+libsilcserver.a:
+       find $(SILCSERVERLIB_DIRS) -type f -name *.lo | xargs \
+       $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) \
+       -version-info $(LIBSILCSERVER_CURRENT):$(LIBSILCSERVER_REVISION):$(LIBSILCSERVER_AGE) \
+       -release $(LIB_BASE_VERSION) -rpath $(DESTDIR)$(libdir) -o libsilcserver.la
+#endif SILC_DIST_SERVERLIB
+
 #ifdef SILC_DIST_TOOLKIT
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = silc.pc silcclient.pc
+pkgconfig_DATA = silc.pc silcclient.pc silcserver.pc
 
-EXTRA_DIST = silc.pc.in silcclient.pc.in
+EXTRA_DIST = silc.pc.in silcclient.pc.in silcserver.pc.in
 #endif SILC_DIST_TOOLKIT
 
 #ifdef SILC_DIST_TOOLKIT
index 0552cfb0e6a55f5006a70abd15917fddecefb390..d27d799a48308bf9e2417823c921ada809db09b6 100644 (file)
@@ -38,12 +38,18 @@ SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcsftp"
 #ifdef SILC_DIST_SIM
 SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcsim"
 #endif SILC_DIST_SIM
-#ifdef SILC_DIST_CLIENT
+#ifdef SILC_DIST_CLIENTLIB
 SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcclient"
-#endif SILC_DIST_CLIENT
+#endif SILC_DIST_CLIENTLIB
 #ifdef SILC_DIST_ASN1
 SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcasn1"
 #endif SILC_DIST_ASN1
+#ifdef SILC_DIST_SKR
+SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcskr"
+#endif SILC_DIST_SKR
+#ifdef SILC_DIST_SERVERLIB
+SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcserver"
+#endif SILC_DIST_SERVERLIB
 
 ##
 ## Library versioning.
@@ -56,8 +62,8 @@ SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcasn1"
 #  - If functions were added, increment [LIB]_AGE
 #  - If functions were removed, set [LIB]_AGE to 0
 #
-# where [LIB] is LIBSILC and LIBSILCCLIENT, and where "functions" means
-# functions public interfaces.
+# where [LIB] is LIBSILC, LIBSILCCLIENT or LIBSILCSERVER, and where 
+# "functions" means functions public interfaces (API).
 #
 # The LIB_BASE_VERSION defines the SILC software major.minor version and
 # it is increment only when these version numbers actually change.
@@ -65,17 +71,22 @@ SILC_LIB_INCLUDES="$SILC_LIB_INCLUDES -I$SILC_TOP_SRCDIR/lib/silcasn1"
 
 # Base version for libraries.  Do not change this unless SILC version
 # changes too.
-LIB_BASE_VERSION=1.0
+LIB_BASE_VERSION=1.1
 
 # libsilc versions
-LIBSILC_CURRENT=5              # prev = 4
+LIBSILC_CURRENT=1              # prev = 0
 LIBSILC_REVISION=0             # prev = 0
-LIBSILC_AGE=3                  # prev = 3
+LIBSILC_AGE=0                  # prev = 0
 
 # libsilcclient versions
-LIBSILCCLIENT_CURRENT=4                # prev = 4
+LIBSILCCLIENT_CURRENT=1                # prev = 0
 LIBSILCCLIENT_REVISION=0       # prev = 0
-LIBSILCCLIENT_AGE=3            # prev = 3
+LIBSILCCLIENT_AGE=0            # prev = 0
+
+# libsilcserver versions
+LIBSILCSERVER_CURRENT=1                # prev = 0
+LIBSILCSERVER_REVISION=0       # prev = 0
+LIBSILCSERVER_AGE=0            # prev = 0
 
 # Substitute the version numbers
 AC_SUBST(LIB_BASE_VERSION)
@@ -85,6 +96,9 @@ AC_SUBST(LIBSILC_AGE)
 AC_SUBST(LIBSILCCLIENT_CURRENT)
 AC_SUBST(LIBSILCCLIENT_REVISION)
 AC_SUBST(LIBSILCCLIENT_AGE)
+AC_SUBST(LIBSILCSERVER_CURRENT)
+AC_SUBST(LIBSILCSERVER_REVISION)
+AC_SUBST(LIBSILCSERVER_AGE)
 
 #ifdef SILC_DIST_SIM
 # SIM modules directory
@@ -159,6 +173,7 @@ lib/silcsftp/tests/Makefile
 AC_CONFIG_FILES(
 lib/silc.pc
 lib/silcclient.pc
+lib/silcserver.pc
 )
 #endif SILC_DIST_TOOLKIT
 
@@ -166,6 +181,13 @@ lib/silcclient.pc
 AC_CONFIG_FILES(lib/silcclient/Makefile)
 #endif SILC_DIST_CLIENTLIB
 
+#ifdef SILC_DIST_SERVERLIB
+AC_CONFIG_FILES(
+lib/silcserver/Makefile
+lib/silcserver/tests/Makefile
+)
+#endif SILC_DIST_SERVERLIB
+
 #ifdef SILC_DIST_ASN1
 AC_CONFIG_FILES(
 lib/silcasn1/Makefile
@@ -175,6 +197,15 @@ lib/silcasn1/tests/Makefile
 )
 #endif SILC_DIST_ASN1
 
+#ifdef SILC_DIST_SKR
+AC_CONFIG_FILES(
+lib/silcskr/Makefile
+#ifdef SILC_DIST_INPLACE
+lib/silcskr/tests/Makefile
+#endif SILC_DIST_INPLACE
+)
+#endif SILC_DIST_SKR
+
 fi     # compile_libs
 
 #endif SILC_DIST_LIB
index 086cbb0964274b9ac8b4b18d7b3a1b16c8deaf4a..8e601568dce900166d58373ae6c69629761b3247 100644 (file)
@@ -1,5 +1,5 @@
 /* Our own convenience getopt.  Public Domain. */
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifndef SILC_EPOC
 #if !defined(HAVE_GETOPT) && !defined(HAVE_GETOPT_H)
index ca5e7413606fb8ed2e215849135cb071f15fc20a..1ddde56c537dfd66a0a7c77d28bb324734235cb8 100644 (file)
@@ -40,7 +40,7 @@ $Id$
 
 #include <stdio.h>
 #include <assert.h>
-//#include "silcincludes.h"
+//#include "silc.h"
 #include "regexpr.h"
 
 #define MACRO_BEGIN do {
index d182fad92fcfdeccb47588a56dcaa62eb27407fe..84349cab5123f4f54e1ebaede83dd93618c174de 100644 (file)
@@ -30,7 +30,7 @@ extern "C"
 #include <stddef.h>            /* size_t */
 #include <stdlib.h>
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifndef uint32_t
 #define uint32_t SilcUInt32
index ba6583172e1a2aec31e50ad4577241258aefd30c..c703cb38e0e8d87dfe402beb208534e129f76f27 100644 (file)
@@ -34,7 +34,7 @@ get access all SILC Client Library routines:
 
 <br />&nbsp;<br />
 <tt>
-#include "silcincludes.h"<br />
+#include "silc.h"<br />
 #include "silcclient.h"
 </tt>
 
@@ -402,7 +402,7 @@ the connections.  The SilcClientOperations are expected to be implemented.
 
 <br />&nbsp;<br />
 <pre>
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 
 int main()
index dfb5cd3ded0c95ac9441ac9ad92a99e01c025745..29b48d38e40e8bb10eebdbba6280d5b87c8f3bac 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcasn1.h"
 #include "silcber.h"
 
index f2d638b9c2118243981032b61290dc47fd0fa840..17354ac154d8601858ff8184488a3a00dda16991 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcasn1.h"
 #include "silcber.h"
 
index 7c8d667d3dd64028ba4f22b6080e9d2898d2b401..350fac946456bc73bf1fa0926784c3bede5d4386 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcasn1.h"
 #include "silcber.h"
 
index 8f7b7e16bab1ef3877e64a152bf48cf026ff8ea9..8f43a3d6b6d11e5f13b8c5744f9bb7427c60ee1c 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* Basic Encoding Rules (BER) encoder and decoder. */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcber.h"
 
 /* Encodes a BER data block into the `ber', which must already have
index c92deee733d3c8f6cf1221c6d7586f6b0685e748..e610be151e30dbd00ff8ddd64f6e2d12ed73cee7 100644 (file)
@@ -1,4 +1,4 @@
-#include "silcincludes.h"
+#include "silc.h"
 
 /*
 silc_asn1_encode(asn1, node,
index 7b980de997ff53c01c57ebf58bc5dcbacd525c3d..e4191d37ee35d1cd48d508ce36f4091f9c5b5492 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 80a8d04df6404536812ec6dc294af79a1efbc92e..f29d91f495a3b8f7cfb082085c88ec24450098e0 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 8f6e320af52b1e08362fb8ca68951c73d42c032d..32d59862e0a1e2d1539f6331c816cc6f33b8cc2f 100644 (file)
@@ -21,7 +21,7 @@
    channel key receiving and setting, and channel private key handling
    routines. */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 58c2419c049ab7964402183e14c0c3f0529a1cee..e4e63da06ae86c092bac6a0704ba4cf382573e10 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 8027bb3c93b5b0e6a17620b678d14962001bfe36..f408e4920bac9864009ae1c7965456be9b5772b3 100644 (file)
@@ -23,7 +23,7 @@
    and in protocol.c. This file implements the client-to-client key
    agreement as defined by the SILC protocol. */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 1f81b435c98c0773b11420be56d56b6b997b944e..c9b6ab632376fb2d175d55a014162bd25942e9a5 100644 (file)
@@ -21,7 +21,7 @@
    important packets sent by the server. They tell different things to the
    client such as nick changes, mode changes etc. */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 47c9d78931b64b7cdcc07ca9c2e9c0970bf827c5..3b43a1f808de058873225f0f786b62d88165696b 100644 (file)
@@ -20,7 +20,7 @@
 /* This file includes the private message sending and receiving routines
    and private message key handling routines. */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 66a6545716d7079a27b2dce2c4c0629bebe5f9f7..5b984234c7f4fe48bfe60bbaf595612ce57765a9 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index f7fb402a6cbd6849b778a586a20c3ec9c4e4df6c..935e5fd03c6186c5c2209ac40effb67ecb90c6f9 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 3cf9a22b85d9e2055e941bd3ee9ef32a21988247..37384977c1e04cf8245669a25f5630a38baff8ba 100644 (file)
@@ -32,7 +32,7 @@
  * received but ID entry does not exist, NULL is sent.
  */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index c8ec53253acb82016e0aea87624119614ca37e08..23674fc591fd42cd5ea803c7d6105c346021349b 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 21d730e9efb0f1d1f773745fe35750b5d4ab0717..c16d9aa3545570e952a347d05f395b51358f7c85 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcclient.h"
 #include "client_internal.h"
 
index 260fe70b615012cf5ee0b746c69b9a297f1ca4b4..678f01daa7e3aee3fcd325d37e29c7d883cf92ac 100644 (file)
@@ -2778,9 +2778,9 @@ SilcAttributePayload silc_client_attribute_add(SilcClient client,
  *
  ***/
 SilcBool silc_client_attribute_del(SilcClient client,
-                              SilcClientConnection conn,
-                              SilcAttribute attribute,
-                              SilcAttributePayload attr);
+                                  SilcClientConnection conn,
+                                  SilcAttribute attribute,
+                                  SilcAttributePayload attr);
 
 /****f* silcclient/SilcClientAPI/silc_client_attributes_get
  *
index 4fe9b7c41ed0c3cc4724b3815d64e7b1e1076f74..a57370495565523b7b787728f8a365b0c59b4f0a 100644 (file)
@@ -19,7 +19,7 @@
 /* Implementation of Argument Payload routines */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcargument.h"
 
 /******************************************************************************
index 304bb8700c5b2d249ce773a32262ea9f418ef767..27f25f7373ebea728ba10e1c984ce7d5e9bca532 100644 (file)
@@ -19,7 +19,7 @@
 /* Implementation of Attribute Payload routines */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcattrs.h"
 
 /******************************************************************************
@@ -121,11 +121,12 @@ silc_attribute_payload_encode_int(SilcAttribute attribute,
     case SILC_ATTRIBUTE_EXTENSION:
     case SILC_ATTRIBUTE_USER_ICON:
       {
-       SilcAttributeObjMime *mime = object;
+       SilcMime mime = object;
        if (object_size != sizeof(*mime))
          return NULL;
-       object = (void *)mime->mime;
-       object_size = mime->mime_len;
+       str = silc_mime_encode(mime, &object_size);
+       if (!str)
+         return NULL;
       }
       break;
 
@@ -416,7 +417,7 @@ const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
 /* Construct digital signature verification data */
 
 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
-                                             bool server_verification,
+                                             SilcBool server_verification,
                                              SilcUInt32 *data_len)
 {
   SilcAttributePayload attr;
@@ -464,11 +465,11 @@ unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
 
 /* Return parsed attribute object */
 
-bool silc_attribute_get_object(SilcAttributePayload payload,
+SilcBool silc_attribute_get_object(SilcAttributePayload payload,
                               void *object, SilcUInt32 object_size)
 {
   SilcUInt16 len;
-  bool ret = FALSE;
+  SilcBool ret = FALSE;
 
   if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
     return FALSE;
@@ -552,11 +553,11 @@ bool silc_attribute_get_object(SilcAttributePayload payload,
   case SILC_ATTRIBUTE_EXTENSION:
   case SILC_ATTRIBUTE_USER_ICON:
     {
-      SilcAttributeObjMime *mime = object;
+      SilcMime mime = object;
       if (object_size != sizeof(*mime))
        break;
-      mime->mime = (const unsigned char *)payload->data;
-      mime->mime_len = payload->data_len;
+      if (!silc_mime_decode(mime, payload->data, payload->data_len))
+       break;
       ret = TRUE;
     }
     break;
index 4c420e36940aad9b724352157abe15e4dfa69f85..b51ca8243b28447fe742a44b7b42db1cd5db36c5 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 - 2003 Pekka Riikonen
+  Copyright (C) 2002 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -67,22 +67,22 @@ typedef SilcUInt8 SilcAttribute;
    comment is the structure or data type that must be used with the
    silc_attribute_get_object function to fetch parsed attribute. */
 #define SILC_ATTRIBUTE_NONE                   0
-#define SILC_ATTRIBUTE_USER_INFO              1 /* SilcVCard */
-#define SILC_ATTRIBUTE_SERVICE                2 /* SilcAttributeObjService */
-#define SILC_ATTRIBUTE_STATUS_MOOD            3 /* SilcAttributeMood */
-#define SILC_ATTRIBUTE_STATUS_FREETEXT        4 /* char * (UTF-8 string) */
-#define SILC_ATTRIBUTE_STATUS_MESSAGE         5 /* SilcAttributeObjMime */
-#define SILC_ATTRIBUTE_PREFERRED_LANGUAGE     6 /* char * (UTF-8 string) */
-#define SILC_ATTRIBUTE_PREFERRED_CONTACT      7 /* SilcAttributeContact */
-#define SILC_ATTRIBUTE_TIMEZONE               8 /* char * (UTF-8 string) */
-#define SILC_ATTRIBUTE_GEOLOCATION            9 /* SilcAttributeObjGeo */
-#define SILC_ATTRIBUTE_DEVICE_INFO            10 /* SilcAttributeObjDevice */
-#define SILC_ATTRIBUTE_EXTENSION              11 /* SilcAttributeObjMime */
-#define SILC_ATTRIBUTE_USER_PUBLIC_KEY        12 /* SilcAttributeObjPk */
-#define SILC_ATTRIBUTE_SERVER_PUBLIC_KEY      13 /* SilcAttributeObjPk */
-#define SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE 14 /* SilcAttributeObjPk */
+#define SILC_ATTRIBUTE_USER_INFO              1   /* SilcVCard */
+#define SILC_ATTRIBUTE_SERVICE                2   /* SilcAttributeObjService */
+#define SILC_ATTRIBUTE_STATUS_MOOD            3   /* SilcAttributeMood */
+#define SILC_ATTRIBUTE_STATUS_FREETEXT        4   /* char * (UTF-8 string) */
+#define SILC_ATTRIBUTE_STATUS_MESSAGE         5   /* SilcMime */
+#define SILC_ATTRIBUTE_PREFERRED_LANGUAGE     6   /* char * (UTF-8 string) */
+#define SILC_ATTRIBUTE_PREFERRED_CONTACT      7   /* SilcAttributeContact */
+#define SILC_ATTRIBUTE_TIMEZONE               8   /* char * (UTF-8 string) */
+#define SILC_ATTRIBUTE_GEOLOCATION            9   /* SilcAttributeObjGeo */
+#define SILC_ATTRIBUTE_DEVICE_INFO            10  /* SilcAttributeObjDevice */
+#define SILC_ATTRIBUTE_EXTENSION              11  /* SilcMime */
+#define SILC_ATTRIBUTE_USER_PUBLIC_KEY        12  /* SilcAttributeObjPk */
+#define SILC_ATTRIBUTE_SERVER_PUBLIC_KEY      13  /* SilcAttributeObjPk */
+#define SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE 14  /* SilcAttributeObjPk */
 #define SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE 15 /* SilcAttributeObjPk */
-#define SILC_ATTRIBUTE_USER_ICON             16 /* SilcAttributeObjMime */
+#define SILC_ATTRIBUTE_USER_ICON             16  /* SilcMime */
 /***/
 
 /* Maximum length of attribute request packet */
@@ -358,7 +358,7 @@ const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
  *
  *    unsigned char *
  *    silc_attribute_get_verify_data(SilcDList attrs,
- *                                   bool server_verification,
+ *                                   SilcBool server_verification,
  *                                   SilcUInt32 *data_len);
  *
  * DESCRIPTION
@@ -373,7 +373,7 @@ const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
  *
  ***/
 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
-                                             bool server_verification,
+                                             SilcBool server_verification,
                                              SilcUInt32 *data_len);
 
 /* Object structures */
@@ -395,29 +395,10 @@ typedef struct SilcAttributeObjServiceStruct {
   SilcUInt32 idle;             /* Idle time in the service */
   char signon[64];             /* Signon date and time (UTC) */
   char address[256];           /* service address */
-  bool status;                 /* online status (TRUE present in service) */
+  SilcBool status;             /* online status (TRUE present in service) */
 } SilcAttributeObjService;
 /***/
 
-/****s* silccore/SilcAttributesAPI/SilcAttributeObjMime
- *
- * NAME
- *
- *    typedef struct { ... } SilcAttributeObjMime;
- *
- * DESCRIPTION
- *
- *    Data type for MIME object as attribute.  The data in the structure
- *    is valid as long as the payload structure is valid.
- *
- * SOURCE
- */
-typedef struct SilcAttributeObjMimeStruct {
-  const unsigned char *mime;   /* MIME buffer */
-  SilcUInt32 mime_len;         /* length of the MIME buffer */
-} SilcAttributeObjMime;
-/***/
-
 /****s* silccore/SilcAttributesAPI/SilcAttributeObjGeo
  *
  * NAME
@@ -500,9 +481,9 @@ typedef struct SilcAttributeObjPkStruct {
  *
  * SYNOPSIS
  *
- *    bool silc_attribute_get_object(SilcAttributePayload payload,
- *                                   void *object,
- *                                   SilcUInt32 object_size);
+ *    SilcBool silc_attribute_get_object(SilcAttributePayload payload,
+ *                                       void *object,
+ *                                       SilcUInt32 object_size);
  *
  * DESCRIPTION
  *
@@ -526,10 +507,15 @@ typedef struct SilcAttributeObjPkStruct {
  *    memset(&dev, 0, sizeof(dev));
  *    if (!silc_attribute_get_object(payload, (void *)&dev, sizeof(dev)))
  *      error();
+ *
+ *    case SILC_ATTRIBUTE_USER_ICON:
+ *    mime = silc_mime_alloc();
+ *    if (!silc_attribute_get_object(payload, (void *)mime, sizeof(*mime)))
+ *      error();
  *    ...
  *
  ***/
-bool silc_attribute_get_object(SilcAttributePayload payload,
-                              void *object, SilcUInt32 object_size);
+SilcBool silc_attribute_get_object(SilcAttributePayload payload,
+                                  void *object, SilcUInt32 object_size);
 
 #endif /* SILCATTRS_H */
index 3e56370b133b91e77a1e88f610c5726faacd9f64..b98f36e84ae7d7e5aa5d42383ad2483b5dc71308 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcauth.h"
 
 /******************************************************************************
@@ -201,24 +201,21 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key,
                                 SilcIdType type, SilcUInt32 *ret_len)
 {
   SilcBuffer buf;
-  unsigned char *pk, *id_data, *ret;
+  unsigned char *pk, id_data[32], *ret;
   SilcUInt32 pk_len, id_len;
 
   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
   if (!pk)
     return NULL;
 
-  id_data = silc_id_id2str(id, type);
-  if (!id_data) {
+  if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &id_len)) {
     silc_free(pk);
     return NULL;
   }
-  id_len = silc_id_get_len(id, type);
 
   buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
   if (!buf) {
     silc_free(pk);
-    silc_free(id_data);
     return NULL;
   }
   silc_buffer_format(buf,
@@ -230,7 +227,6 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key,
   ret = silc_buffer_steal(buf, ret_len);
 
   silc_buffer_free(buf);
-  silc_free(id_data);
   silc_free(pk);
 
   return ret;
@@ -294,7 +290,7 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
     return NULL;
 
   /* Allocate PKCS object */
-  if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
+  if (!silc_pkcs_alloc(private_key->name, SILC_PKCS_SILC, &pkcs)) {
     memset(tmp, 0, tmp_len);
     silc_free(tmp);
     return NULL;
@@ -327,9 +323,10 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
 /* Verifies the authentication data. Returns TRUE if authentication was
    successful. */
 
-bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
-                                     SilcPublicKey public_key, SilcHash hash,
-                                     const void *id, SilcIdType type)
+SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
+                                         SilcPublicKey public_key,
+                                         SilcHash hash,
+                                         const void *id, SilcIdType type)
 {
   unsigned char *tmp;
   SilcUInt32 tmp_len;
@@ -347,7 +344,7 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
   }
 
   /* Allocate PKCS object */
-  if (!silc_pkcs_alloc(public_key->name, &pkcs)) {
+  if (!silc_pkcs_alloc(public_key->name, SILC_PKCS_SILC, &pkcs)) {
     memset(tmp, 0, tmp_len);
     silc_free(tmp);
     return FALSE;
@@ -376,11 +373,11 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
 
 /* Same as above but the payload is not parsed yet. This will parse it. */
 
-bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
-                                          SilcUInt32 payload_len,
-                                          SilcPublicKey public_key,
-                                          SilcHash hash,
-                                          const void *id, SilcIdType type)
+SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
+                                              SilcUInt32 payload_len,
+                                              SilcPublicKey public_key,
+                                              SilcHash hash,
+                                              const void *id, SilcIdType type)
 {
   SilcAuthPayload auth_payload;
   int ret;
@@ -406,9 +403,9 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
    authentication then the `auth_data' is the SilcPublicKey and the
    `auth_data_len' is ignored. */
 
-bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
-                     const void *auth_data, SilcUInt32 auth_data_len,
-                     SilcHash hash, const void *id, SilcIdType type)
+SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
+                         const void *auth_data, SilcUInt32 auth_data_len,
+                         SilcHash hash, const void *id, SilcIdType type)
 {
   SILC_LOG_DEBUG(("Verifying authentication"));
 
@@ -453,14 +450,15 @@ bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
 
 /* Same as above but parses the authentication payload before verify. */
 
-bool silc_auth_verify_data(const unsigned char *payload,
-                          SilcUInt32 payload_len,
-                          SilcAuthMethod auth_method, const void *auth_data,
-                          SilcUInt32 auth_data_len, SilcHash hash,
-                          const void *id, SilcIdType type)
+SilcBool silc_auth_verify_data(const unsigned char *payload,
+                              SilcUInt32 payload_len,
+                              SilcAuthMethod auth_method,
+                              const void *auth_data,
+                              SilcUInt32 auth_data_len, SilcHash hash,
+                              const void *id, SilcIdType type)
 {
   SilcAuthPayload auth_payload;
-  bool ret;
+  SilcBool ret;
 
   auth_payload = silc_auth_payload_parse(payload, payload_len);
   if (!auth_payload || (auth_payload->auth_len == 0))
index 29101966d7ce6208f7b79055477b6ca1a66cd64d..7a2e882a0dd680f1967d5bb0e95a98a9a7d0d97b 100644 (file)
@@ -244,7 +244,7 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
  *
  * SYNOPSIS
  *
- *    bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
+ *    SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
  *                                          SilcPublicKey public_key,
  *                                          SilcHash hash,
  *                                          const void *id, SilcIdType type);
@@ -255,7 +255,7 @@ silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
  *    successful.
  *
  ***/
-bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
+SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
                                      SilcPublicKey public_key, SilcHash hash,
                                      const void *id, SilcIdType type);
 
@@ -263,7 +263,7 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
  *
  * SYNOPSIS
  *
- *    bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
+ *    SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *                                               SilcUInt32 payload_len,
  *                                               SilcPublicKey public_key,
  *                                               SilcHash hash,
@@ -277,7 +277,7 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
  *    was successful.
  *
  ***/
-bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
+SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
                                           SilcUInt32 payload_len,
                                           SilcPublicKey public_key,
                                           SilcHash hash,
@@ -287,7 +287,7 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *
  * SYNOPSIS
  *
- *    bool silc_auth_verify(SilcAuthPayload payload,
+ *    SilcBool silc_auth_verify(SilcAuthPayload payload,
  *                          SilcAuthMethod auth_method,
  *                          const void *auth_data, SilcUInt32 auth_data_len,
  *                          SilcHash hash, const void *id, SilcIdType type);
@@ -302,7 +302,7 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *    `auth_data' is the SilcPublicKey and the `auth_data_len' is ignored.
  *
  ***/
-bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
+SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
                      const void *auth_data, SilcUInt32 auth_data_len,
                      SilcHash hash, const void *id, SilcIdType type);
 
@@ -310,7 +310,7 @@ bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
  *
  * SYNOPSIS
  *
- *    bool silc_auth_verify_data(const unsigned char *payload,
+ *    SilcBool silc_auth_verify_data(const unsigned char *payload,
  *                               SilcUInt32 payload_len,
  *                               SilcAuthMethod auth_method,
  *                               const void *auth_data,
@@ -328,7 +328,7 @@ bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
  *    `auth_data' is the SilcPublicKey and the `auth_data_len' is ignored.
  *
  ***/
-bool silc_auth_verify_data(const unsigned char *payload,
+SilcBool silc_auth_verify_data(const unsigned char *payload,
                           SilcUInt32 payload_len,
                           SilcAuthMethod auth_method, const void *auth_data,
                           SilcUInt32 auth_data_len, SilcHash hash,
index 457662226c312590df5b57d01344c8328357c73a..687d5ef7f0ab69d5816cc4cf5bfe89871a8e3039 100644 (file)
@@ -19,7 +19,7 @@
 /* Channel Payload and Channel Key Payload implementations. */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcchannel.h"
 
 /******************************************************************************
@@ -210,10 +210,12 @@ unsigned char *silc_channel_get_id(SilcChannelPayload payload,
 
 /* Return the channel ID as parsed ID. */
 
-SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
+SilcBool silc_channel_get_id_parse(SilcChannelPayload payload,
+                                  SilcChannelID *ret_channel_id)
 {
   return silc_id_str2id(payload->channel_id, payload->id_len,
-                       SILC_ID_CHANNEL);
+                       SILC_ID_CHANNEL, ret_channel_id,
+                       sizeof(SilcChannelID));
 }
 
 /* Return the mode. The mode is arbitrary. It can be the mode of the
index 385f6807b452361a4821192422600f17fadb663a..c9c7d58318572f0d4e05387f451ca453523b1921 100644 (file)
@@ -1,15 +1,15 @@
 /*
+
   silcchannel.h
+
   Author: Pekka Riikonen <priikone@silcnet.org>
+
   Copyright (C) 1997 - 2005 Pekka Riikonen
+
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.
+
   This program 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
@@ -37,7 +37,7 @@
 /****s* silccore/SilcChannelAPI/SilcChannelPayload
  *
  * NAME
- * 
+ *
  *    typedef struct SilcChannelPayloadStruct *SilcChannelPayload;
  *
  * DESCRIPTION
@@ -53,7 +53,7 @@ typedef struct SilcChannelPayloadStruct *SilcChannelPayload;
 /****s* silccore/SilcChannelAPI/SilcChannelKeyPayload
  *
  * NAME
- * 
+ *
  *    typedef struct SilcChannelKeyPayloadStruct *SilcChannelKeyPayload;
  *
  * DESCRIPTION
@@ -72,7 +72,7 @@ typedef struct SilcChannelKeyPayloadStruct *SilcChannelKeyPayload;
  *
  * SYNOPSIS
  *
- *    SilcChannelPayload 
+ *    SilcChannelPayload
  *    silc_channel_payload_parse(const unsigned char *payload,
  *                               SilcUInt32 payload_len);
  *
@@ -184,16 +184,17 @@ unsigned char *silc_channel_get_id(SilcChannelPayload payload,
  *
  * SYNOPSIS
  *
- *    SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload);
+ *    SilcBool silc_channel_get_id_parse(SilcChannelPayload payload,
+ *                                       SilcChannelID *ret_channel_id);
  *
  * DESCRIPTION
  *
  *    Return the Channel ID as parsed ID. This is equivalent to the
- *    silc_channel_get_id execpt that the ID is already parsed. The caller
- *    must free the parsed Channel ID.
+ *    silc_channel_get_id execpt that the ID is already parsed.
  *
  ***/
-SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload);
+SilcBool silc_channel_get_id_parse(SilcChannelPayload payload,
+                                  SilcChannelID *ret_channel_id);
 
 /****f* silccore/SilcChannelAPI/silc_channel_get_mode
  *
@@ -214,17 +215,17 @@ SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload);
  *
  * SYNOPSIS
  *
- *    SilcChannelKeyPayload 
+ *    SilcChannelKeyPayload
  *    silc_channel_key_payload_parse(const unsigned char *payload,
  *                                   uin32 payload_len);
  *
  * DESCRIPTION
  *
- *     Parses channel key payload returning new channel key payload 
+ *     Parses channel key payload returning new channel key payload
  *     structure.
  *
  ***/
-SilcChannelKeyPayload 
+SilcChannelKeyPayload
 silc_channel_key_payload_parse(const unsigned char *payload,
                               SilcUInt32 payload_len);
 
@@ -241,7 +242,7 @@ silc_channel_key_payload_parse(const unsigned char *payload,
  *
  * DESCRIPTION
  *
- *    Encodes channel key payload into a buffer and returns it. This is used 
+ *    Encodes channel key payload into a buffer and returns it. This is used
  *    to add channel key payload into a packet.
  *
  ***/
@@ -269,7 +270,7 @@ void silc_channel_key_payload_free(SilcChannelKeyPayload payload);
  *
  * SYNOPSIS
  *
- *    unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
+ *    unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
  *                                           SilcUInt32 *id_len);
  *
  * DESCRIPTION
@@ -278,7 +279,7 @@ void silc_channel_key_payload_free(SilcChannelKeyPayload payload);
  *    free it.
  *
  ***/
-unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
+unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
                                       SilcUInt32 *id_len);
 
 /****f* silccore/SilcChannelAPI/silc_channel_key_get_cipher
index d39ed97c4e24d5f9d80d4b81cb689c9a6dae4227..83dbde8cf6263e1f218019c410123a572747e1cc 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silccommand.h"
 
 /******************************************************************************
@@ -83,7 +83,8 @@ SilcCommandPayload silc_command_payload_parse(const unsigned char *payload,
 
   silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN);
   if (args_num) {
-    newp->args = silc_argument_payload_parse(buffer.data, silc_buffer_len(&buffer),
+    newp->args = silc_argument_payload_parse(buffer.data,
+                                            silc_buffer_len(&buffer),
                                             args_num);
     if (!newp->args) {
       silc_free(newp);
@@ -134,7 +135,8 @@ SilcBuffer silc_command_payload_encode(SilcCommand cmd,
   if (argc) {
     silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
     silc_buffer_format(buffer,
-                      SILC_STR_UI_XNSTRING(args->data, silc_buffer_len(args)),
+                      SILC_STR_UI_XNSTRING(args->data,
+                                           silc_buffer_len(args)),
                       SILC_STR_END);
     silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
     silc_buffer_free(args);
@@ -182,7 +184,8 @@ SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
   if (args) {
     silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
     silc_buffer_format(buffer,
-                      SILC_STR_UI_XNSTRING(args->data, silc_buffer_len(args)),
+                      SILC_STR_UI_XNSTRING(args->data,
+                                           silc_buffer_len(args)),
                       SILC_STR_END);
     silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
     silc_buffer_free(args);
@@ -397,7 +400,7 @@ SilcUInt16 silc_command_get_ident(SilcCommandPayload payload)
 
 /* Return command status */
 
-bool silc_command_get_status(SilcCommandPayload payload,
+SilcBool silc_command_get_status(SilcCommandPayload payload,
                             SilcStatus *status,
                             SilcStatus *error)
 {
index f1d12909d1530636ed5ab531f90be8ef1f68a9fe..8c1094ff861d41248ccde10ba37c04038d24a913 100644 (file)
@@ -382,7 +382,7 @@ SilcUInt16 silc_command_get_ident(SilcCommandPayload payload);
  *
  * SYNOPSIS
  *
- *    bool silc_command_get_status(SilcCommandPayload payload,
+ *    SilcBool silc_command_get_status(SilcCommandPayload payload,
  *                                 SilcStatus *status,
  *                                 SilcStatus *error);
  *
@@ -396,7 +396,7 @@ SilcUInt16 silc_command_get_ident(SilcCommandPayload payload);
  *    which indicates that there will be list of errors.
  *
  ***/
-bool silc_command_get_status(SilcCommandPayload payload,
+SilcBool silc_command_get_status(SilcCommandPayload payload,
                             SilcStatus *status,
                             SilcStatus *error);
 
index 1d6b59b9fafdbe09e8f7885b0c606e7d0705cf6e..1e5727bc215bd96d94831b3aa7119e9e5b71ff97 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcid.h"
 
 /* ID lengths (in bytes) without the IP address part */
@@ -64,7 +64,8 @@ SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
 
   silc_buffer_pull(&buffer, 4);
 
-  if (newp->len > silc_buffer_len(&buffer) || newp->len > SILC_PACKET_MAX_ID_LEN)
+  if (newp->len > silc_buffer_len(&buffer) ||
+      newp->len > SILC_PACKET_MAX_ID_LEN)
     goto err;
 
   ret = silc_buffer_unformat(&buffer,
@@ -73,8 +74,6 @@ SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
   if (ret == -1)
     goto err;
 
-  silc_buffer_push(&buffer, 4);
-
   return newp;
 
  err:
@@ -85,15 +84,15 @@ SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
 
 /* Return the ID directly from the raw payload data. */
 
-void *silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
-                              SilcIdType *ret_type)
+SilcBool silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
+                                 SilcIdType *ret_type, void *ret_id,
+                                 SilcUInt32 ret_id_size)
 {
   SilcBufferStruct buffer;
   SilcIdType type;
   SilcUInt16 idlen;
   unsigned char *id_data;
   int ret;
-  void *id;
 
   silc_buffer_set(&buffer, (unsigned char *)data, len);
   ret = silc_buffer_unformat(&buffer,
@@ -117,16 +116,17 @@ void *silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
   if (ret == -1)
     goto err;
 
-  id = silc_id_str2id(id_data, idlen, type);
+  if (!silc_id_str2id(id_data, idlen, type, ret_id, ret_id_size))
+    goto err;
 
   if (ret_type)
     *ret_type = type;
 
-  return id;
+  return TRUE;
 
  err:
   SILC_LOG_DEBUG(("Error parsing ID payload"));
-  return NULL;
+  return FALSE;
 }
 
 /* Encodes ID Payload */
@@ -134,14 +134,13 @@ void *silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
 SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type)
 {
   SilcBuffer buffer;
-  unsigned char *id_data;
+  unsigned char id_data[32];
   SilcUInt32 len;
 
-  id_data = silc_id_id2str(id, type);
-  len = silc_id_get_len(id, type);
+  if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &len))
+    return NULL;
   buffer = silc_id_payload_encode_data((const unsigned char *)id_data,
                                       len, type);
-  silc_free(id_data);
   return buffer;
 }
 
@@ -180,10 +179,13 @@ SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
 
 /* Get ID */
 
-void *silc_id_payload_get_id(SilcIDPayload payload)
+SilcBool silc_id_payload_get_id(SilcIDPayload payload, void *ret_id,
+                               SilcUInt32 ret_id_len)
 {
-  return payload ? silc_id_str2id(payload->id, payload->len,
-                                  payload->type) : NULL;
+  if (!payload)
+    return FALSE;
+  return silc_id_str2id(payload->id, payload->len, payload->type,
+                       ret_id, ret_id_len);
 }
 
 /* Get raw ID data. Data is duplicated. */
@@ -205,62 +207,56 @@ SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload)
 
 /* Converts ID to string. */
 
-unsigned char *silc_id_id2str(const void *id, SilcIdType type,
-                             SilcUInt32 *ret_id_len)
+SilcBool silc_id_id2str(const void *id, SilcIdType type,
+                       unsigned char *ret_id, SilcUInt32 ret_id_size,
+                       SilcUInt32 *ret_id_len)
 {
-  unsigned char *ret_id;
   SilcServerID *server_id;
   SilcClientID *client_id;
   SilcChannelID *channel_id;
   SilcUInt32 id_len = silc_id_get_len(id, type);
 
+  if (id_len > ret_id_size)
+    return FALSE;
+
   if (ret_id_len)
     *ret_id_len = id_len;
 
   if (id_len > SILC_PACKET_MAX_ID_LEN)
-    return NULL;
+    return FALSE;
 
   switch(type) {
   case SILC_ID_SERVER:
     server_id = (SilcServerID *)id;
-    ret_id = silc_calloc(id_len, sizeof(unsigned char));
-    if (!ret_id)
-      return NULL;
     memcpy(ret_id, server_id->ip.data, server_id->ip.data_len);
     SILC_PUT16_MSB(server_id->port, &ret_id[server_id->ip.data_len]);
     SILC_PUT16_MSB(server_id->rnd, &ret_id[server_id->ip.data_len + 2]);
-    return ret_id;
+    return TRUE;
     break;
   case SILC_ID_CLIENT:
     client_id = (SilcClientID *)id;
-    ret_id = silc_calloc(id_len, sizeof(unsigned char));
-    if (!ret_id)
-      return NULL;
     memcpy(ret_id, client_id->ip.data, client_id->ip.data_len);
     ret_id[client_id->ip.data_len] = client_id->rnd;
     memcpy(&ret_id[client_id->ip.data_len + 1], client_id->hash,
           CLIENTID_HASH_LEN);
-    return ret_id;
+    return TRUE;
     break;
   case SILC_ID_CHANNEL:
     channel_id = (SilcChannelID *)id;
-    ret_id = silc_calloc(id_len, sizeof(unsigned char));
-    if (!ret_id)
-      return NULL;
     memcpy(ret_id, channel_id->ip.data, channel_id->ip.data_len);
     SILC_PUT16_MSB(channel_id->port, &ret_id[channel_id->ip.data_len]);
     SILC_PUT16_MSB(channel_id->rnd, &ret_id[channel_id->ip.data_len + 2]);
-    return ret_id;
+    return TRUE;
     break;
   }
 
-  return NULL;
+  return FALSE;
 }
 
 /* Converts string to a ID */
 
-bool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
-                   SilcIdType type, void *ret_id)
+SilcBool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
+                       SilcIdType type, void *ret_id, SilcUInt32 ret_id_size)
 {
   if (id_len > SILC_PACKET_MAX_ID_LEN)
     return FALSE;
@@ -274,6 +270,10 @@ bool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
          id_len != ID_SERVER_LEN_PART + 16)
        return FALSE;
 
+      if (ret_id_size < sizeof(SilcServerID))
+       return FALSE;
+
+      memset(ret_id, 0, ret_id_size);
       memcpy(server_id->ip.data, id, (id_len > ID_SERVER_LEN_PART + 4 ?
                                      16 : 4));
       server_id->ip.data_len = (id_len > ID_SERVER_LEN_PART + 4 ? 16 : 4);
@@ -290,6 +290,10 @@ bool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
          id_len != ID_CLIENT_LEN_PART + 16)
        return FALSE;
 
+      if (ret_id_size < sizeof(SilcClientID))
+       return FALSE;
+
+      memset(ret_id, 0, ret_id_size);
       memcpy(client_id->ip.data, id, (id_len > ID_CLIENT_LEN_PART + 4 ?
                                      16 : 4));
       client_id->ip.data_len = (id_len > ID_CLIENT_LEN_PART + 4 ? 16 : 4);
@@ -307,6 +311,10 @@ bool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
          id_len != ID_CHANNEL_LEN_PART + 16)
        return FALSE;
 
+      if (ret_id_size < sizeof(SilcChannelID))
+       return FALSE;
+
+      memset(ret_id, 0, ret_id_size);
       memcpy(channel_id->ip.data, id, (id_len > ID_CHANNEL_LEN_PART + 4 ?
                                       16 : 4));
       channel_id->ip.data_len = (id_len > ID_CHANNEL_LEN_PART + 4 ? 16 : 4);
index f98744805273d286d75c750dab095ccae874c554..8bdf6cc0e2e019bcc9db230e7d29de19e311ba01 100644 (file)
@@ -107,18 +107,20 @@ SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
  *
  * SYNOPSIS
  *
- *    void *silc_id_payload_parse_id(const unsigned char *data,
- *                                   SilcUInt32 len,
- *                                   SilcIdType *type);
+ *    SilcBool silc_id_payload_parse_id(const unsigned char *data,
+ *                                      SilcUInt32 len,
+ *                                      SilcIdType *type, void *ret_id,
+ *                                      SilcUInt32 ret_id_size);
  *
  * DESCRIPTION
  *
- *    Return ID directly from the raw ID Payload data buffer. The
- *    caller must free the returned ID.
+ *    Return ID directly from the raw ID Payload data buffer.  This does
+ *    not allocate any memory.
  *
  ***/
-void *silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
-                              SilcIdType *type);
+SilcBool silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
+                                 SilcIdType *type, void *ret_id,
+                                 SilcUInt32 ret_id_size);
 
 /****f* silccore/SilcIDAPI/silc_id_payload_encode
  *
@@ -181,15 +183,16 @@ SilcIdType silc_id_payload_get_type(SilcIDPayload payload);
  *
  * SYNOPSIS
  *
- *    void *silc_id_payload_get_id(SilcIDPayload payload);
+ *    SilcBool silc_id_payload_get_id(SilcIDPayload payload, void *ret_id,
+ *                                    SilcUInt32 ret_id_len);
  *
  * DESCRIPTION
  *
- *    Returns the ID in the ID Payload. The caller must free the
- *    returned ID.
+ *    Returns the ID in the ID Payload. This does not allocate any memory.
  *
  ***/
-void *silc_id_payload_get_id(SilcIDPayload payload);
+SilcBool silc_id_payload_get_id(SilcIDPayload payload, void *ret_id,
+                               SilcUInt32 ret_id_len);
 
 /****f* silccore/SilcIDAPI/silc_id_payload_get_data
  *
@@ -416,34 +419,38 @@ typedef struct {
  *
  * SYNOPSIS
  *
- *    unsigned char *silc_id_id2str(const void *id, SilcIdType type,
- *                                  SilcUInt32 *ret_id_len);
+ *    SilcBool silc_id_id2str(const void *id, SilcIdType type,
+ *                            unsigned char *ret_id, SilcUInt32 ret_id_size,
+ *                            SilcUInt32 *ret_id_len);
  *
  * DESCRIPTION
  *
  *    Converts an ID of type `type' to data. This can be used to
- *    convert the ID's to data for inclusion in the packets.  Use the
- *    silc_id_get_len to get the length of the ID.
+ *    convert the ID's to data for inclusion in the packets.  This does
+ *    not allocate any memory.
  *
  ***/
-unsigned char *silc_id_id2str(const void *id, SilcIdType type,
-                             SilcUInt32 *ret_id_len);
+SilcBool silc_id_id2str(const void *id, SilcIdType type,
+                       unsigned char *ret_id, SilcUInt32 ret_id_size,
+                       SilcUInt32 *ret_id_len);
 
 /****f* silccore/SilcIDAPI/silc_id_str2id
  *
  * SYNOPSIS
  *
- *    bool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
- *                        SilcIdType type, void *ret_id);
+ *    SilcBool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
+ *                            SilcIdType type, void *ret_id,
+ *                            SilcUInt32 ret_id_size);
  *
  * DESCRIPTION
  *
  *    Converts ID data string to an ID. This can be used to get the
- *    ID out of data that has been taken for example from packet.
+ *    ID out of data that has been taken for example from packet.  This
+ *    does not allocate any memory.
  *
  ***/
-bool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
-                   SilcIdType type, void *ret_id);
+SilcBool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
+                       SilcIdType type, void *ret_id, SilcUInt32 ret_id_size);
 
 /****f* silccore/SilcIDAPI/silc_id_get_len
  *
index a2a279cc4567b48abfc8f98439e655b49b47cb04..accb09176866d248e5fbc7a54e16443291c9928b 100644 (file)
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcidcache.h"
 
-/* Static prototypes */
-static void silc_idcache_destructor(void *key, void *context,
-                                   void *user_context);
-static SilcIDCacheList silc_idcache_list_alloc();
-static void silc_idcache_list_add(SilcIDCacheList list,
-                                 SilcIDCacheEntry cache);
+/************************** Types and definitions ***************************/
 
-/*
-   SILC ID Cache object.
-
-   This is context for the ID cache system. This includes all the cache
-   entries and other internal data. This is read-only object and not
-   visible outside this cache system.
-
-   Fields are as follows:
-
-   SilcHashTable id_table
-
-       Hash table using the ID as the key.
-
-   SilcHashTable name_table
-
-       Hash table using the name as the key.
+/* ID Cache context */
+struct SilcIDCacheStruct {
+  SilcHashTable id_table;           /* ID hash table */
+  SilcHashTable name_table;         /* Name hash table */
+  SilcHashTable context_table;      /* Context hash table */
+  SilcIDCacheDestructor destructor;  /* Entry destructor */
+  void *context;                    /* Destructor context */
+  SilcIdType id_type;               /* Type of ID cache */
+};
 
-   SilcHashTable context_table
 
-       Hash table using the context as the key.
+/************************ Static utility functions **************************/
 
-   SilcIDCacheDestructor destructor
+/* Callback that is called by the hash table routine when traversing
+   entries in the hash table. */
 
-       Destructor callback that is called when an cache entry expires or is
-       purged from the ID cache. The application must not free cache entry
-       because the library will do it automatically. The appliation, however,
-       is responsible of freeing any data in the entry.
+static void silc_idcache_get_all_foreach(void *key, void *context,
+                                        void *user_context)
+{
+  SilcList *list = user_context;
+  if (!context)
+    return;
+  silc_list_add(*list, context);
+}
 
-   SilcIdType id_type
+/* Cache entry destructor */
 
-       Indicates the type of the ID's this cache holds.
+static void silc_idcache_destructor(SilcIDCache cache,
+                                   SilcIDCacheEntry entry,
+                                   void *app_context)
+{
+  if (cache->destructor)
+    cache->destructor(cache, entry, cache->destructor, app_context);
 
-*/
-struct SilcIDCacheStruct {
-  SilcHashTable id_table;
-  SilcHashTable name_table;
-  SilcHashTable context_table;
-  SilcIDCacheDestructor destructor;
-  void *context;
-  SilcIdType type;
-  unsigned int delete_id : 1;
-  unsigned int delete_name : 1;
-};
+  memset(entry, 'F', sizeof(*entry));
+  silc_free(entry);
+}
 
-/*
-   ID Cache list.
 
-   This is returned when searching the cache. Enumeration functions are
-   provided to traverse the list; actually this is used as table not as
-   list. :)
+/****************************** Public API **********************************/
 
-   By default the found cache entries are saved into the static cache
-   table to provide access without reallocation. However, if the static
-   table is full, rest of the cache entries are dynamically allocated
-   into `cache_dyn' table. Traversing functions automatically handles
-   these situations.
-
-*/
-struct SilcIDCacheListStruct {
-  SilcIDCacheEntry cache[128];
-  SilcIDCacheEntry *cache_dyn;
-  SilcUInt32 cache_dyn_count;
-  SilcUInt32 cache_count;
-  SilcUInt32 pos;
-  bool dyn;
-};
-
-/* Allocates new ID cache object. The initial amount of allocated entries
-   can be sent as argument. If `count' is 0 the system uses default values.
-   The `id_type' defines the types of the ID's that will be saved to the
-   cache. */
+/* Allocates new ID cache object. */
 
 SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
                               SilcIDCacheDestructor destructor,
-                              void *destructor_context,
-                              bool delete_id, bool delete_name)
+                              void *destructor_context)
 {
   SilcIDCache cache;
 
@@ -112,12 +77,12 @@ SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
   cache = silc_calloc(1, sizeof(*cache));
   if (!cache)
     return NULL;
+
   cache->id_table = silc_hash_table_alloc(count, silc_hash_id,
                                          SILC_32_TO_PTR(id_type),
                                          silc_hash_id_compare,
                                          SILC_32_TO_PTR(id_type),
-                                         silc_idcache_destructor,
-                                         cache, TRUE);
+                                         NULL, NULL, TRUE);
   cache->name_table = silc_hash_table_alloc(count, silc_hash_utf8_string, NULL,
                                            silc_hash_utf8_compare, NULL,
                                            NULL, NULL, TRUE);
@@ -125,9 +90,7 @@ SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
                                               NULL, NULL, NULL, NULL, TRUE);
   cache->destructor = destructor;
   cache->context = destructor_context;
-  cache->type = id_type;
-  cache->delete_id = delete_id;
-  cache->delete_name = delete_name;
+  cache->id_type = id_type;
 
   if (!cache->id_table || !cache->name_table || !cache->context_table) {
     if (cache->id_table)
@@ -147,346 +110,198 @@ SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
 
 void silc_idcache_free(SilcIDCache cache)
 {
-  if (cache) {
-    silc_hash_table_free(cache->id_table);
-    silc_hash_table_free(cache->name_table);
-    silc_hash_table_free(cache->context_table);
-    silc_free(cache);
-  }
+  silc_hash_table_free(cache->id_table);
+  silc_hash_table_free(cache->name_table);
+  silc_hash_table_free(cache->context_table);
+  silc_free(cache);
 }
 
-/* Add new entry to the cache. Returns TRUE if the entry was added and
-   FALSE if it could not be added. The `name' is the name associated with
-   the ID, the `id' the actual ID and the `context' a used specific context.
-   If the `expire' is TRUE the entry expires in default time and if FALSE
-   the entry never expires from the cache. */
+/* Add new entry to cache */
 
-bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
-                     void *context, int expire, SilcIDCacheEntry *ret)
+SilcIDCacheEntry
+silc_idcache_add(SilcIDCache cache, char *name, void *id, void *context)
 {
   SilcIDCacheEntry c;
 
-  SILC_LOG_DEBUG(("Adding cache entry"));
+  if (!id)
+    return NULL;
 
   /* Allocate new cache entry */
   c = silc_calloc(1, sizeof(*c));
   if (!c)
-    return FALSE;
+    return NULL;
+
   c->id = id;
   c->name = name;
-  c->expire = expire;
   c->context = context;
 
+  SILC_LOG_DEBUG(("Adding cache entry %p", c));
+
   /* Add the new entry to the hash tables */
 
-  if (id)
-    silc_hash_table_add(cache->id_table, id, c);
+  if (id) {
+    if (silc_idcache_find_by_id_one(cache, id, NULL)) {
+      SILC_LOG_ERROR(("Attempted to add same ID twice to ID Cache"));
+      goto err;
+    }
+    if (!silc_hash_table_add(cache->id_table, id, c))
+      goto err;
+  }
   if (name)
-    silc_hash_table_add(cache->name_table, name, c);
+    if (!silc_hash_table_add(cache->name_table, name, c))
+      goto err;
   if (context)
-    silc_hash_table_add(cache->context_table, context, c);
+    if (!silc_hash_table_add(cache->context_table, context, c))
+      goto err;
 
-  if (ret)
-    *ret = c;
+  return c;
 
-  return TRUE;
-}
-
-/* Destructor for the ID Cache entry */
+ err:
+  if (c->name)
+    silc_hash_table_del_by_context(cache->name_table, c->name, c);
+  if (c->context)
+    silc_hash_table_del_by_context(cache->context_table, c->context, c);
+  if (c->id)
+    silc_hash_table_del_by_context(cache->id_table, c->id, c);
+  silc_free(c);
 
-static void silc_idcache_destructor(void *key, void *context,
-                                   void *user_context)
-{
-  SilcIDCacheEntry c = context;
-  if (c) {
-    SilcIDCache cache = user_context;
-    if (cache) {
-      if (cache->delete_id)
-       silc_free(c->id);
-      if (cache->delete_name)
-       silc_free(c->name);
-    }
-    memset(c, 'F', sizeof(*c));
-    silc_free(c);
-  }
+  return NULL;
 }
 
 /* Delete cache entry from cache. */
 
-bool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
+SilcBool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry entry,
+                         void *app_context)
 {
-  bool ret = FALSE;
-
-  SILC_LOG_DEBUG(("Deleting cache entry"));
-
-  if (old->name)
-    ret = silc_hash_table_del_by_context(cache->name_table, old->name, old);
-  if (old->context)
-    ret = silc_hash_table_del(cache->context_table, old->context);
-  if (old->id)
-    ret = silc_hash_table_del(cache->id_table, old->id);
-  else {
-    silc_idcache_destructor(NULL, old, NULL);
-    ret = TRUE;
-  }
-
-  return ret;
-}
+  SilcBool ret = FALSE;
 
-/* Deletes ID cache entry by ID. */
+  SILC_LOG_DEBUG(("Deleting cache entry %p", entry));
 
-bool silc_idcache_del_by_id(SilcIDCache cache, void *id)
-{
-  SilcIDCacheEntry c;
+  if (entry->name)
+    ret = silc_hash_table_del_by_context(cache->name_table, entry->name,
+                                        entry);
+  if (entry->context)
+    ret = silc_hash_table_del_by_context(cache->context_table, entry->context,
+                                        entry);
+  if (entry->id)
+    ret = silc_hash_table_del_by_context(cache->id_table, entry->id,
+                                        entry);
 
-  if (!silc_hash_table_find(cache->id_table, id, NULL, (void *)&c))
-    return FALSE;
+  if (ret)
+    silc_idcache_destructor(cache, entry, app_context);
 
-  return silc_idcache_del(cache, c);
+  return ret;
 }
 
-/* Same as above but with specific hash and comparison functions. If the
-   functions are NULL then default values are used. */
+/* Deletes ID cache entry by ID. */
 
-bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
-                               SilcHashFunction hash,
-                               void *hash_context,
-                               SilcHashCompare compare,
-                               void *compare_context)
+SilcBool silc_idcache_del_by_id(SilcIDCache cache, void *id,
+                               void *app_context)
 {
   SilcIDCacheEntry c;
-  bool ret = FALSE;
-
-  SILC_LOG_DEBUG(("Deleting cache entry"));
 
-  if (!silc_hash_table_find_ext(cache->id_table, id, NULL, (void *)&c,
-                               hash, hash_context, compare,
-                               compare_context))
+  if (!silc_hash_table_find(cache->id_table, id, NULL, (void **)&c))
     return FALSE;
 
-  if (c->name)
-    ret = silc_hash_table_del_by_context(cache->name_table, c->name, c);
-  if (c->context)
-    ret = silc_hash_table_del(cache->context_table, c->context);
-  if (c->id)
-    ret = silc_hash_table_del_ext(cache->id_table, c->id, hash,
-                                 hash_context, compare, compare_context,
-                                 NULL, NULL);
-  return ret;
+  return silc_idcache_del(cache, c, app_context);
 }
 
 /* Deletes ID cache entry by context. */
 
-bool silc_idcache_del_by_context(SilcIDCache cache, void *context)
+SilcBool silc_idcache_del_by_context(SilcIDCache cache, void *context,
+                                    void *app_context)
 {
   SilcIDCacheEntry c;
-  bool ret = FALSE;
 
-  SILC_LOG_DEBUG(("Deleting cache entry"));
-
-  if (!silc_hash_table_find(cache->context_table, context, NULL, (void *)&c))
+  if (!silc_hash_table_find(cache->context_table, context, NULL, (void **)&c))
     return FALSE;
 
-  if (c->name)
-    ret = silc_hash_table_del_by_context(cache->name_table, c->name, c);
-  if (c->context)
-    ret = silc_hash_table_del(cache->context_table, c->context);
-  if (c->id)
-    ret = silc_hash_table_del_by_context(cache->id_table, c->id, c);
-  else {
-    silc_idcache_destructor(NULL, c, NULL);
-    ret = TRUE;
-  }
-
-  return ret;
+  return silc_idcache_del(cache, c, app_context);
 }
 
-/* Deletes all ID entries from cache. Free's memory as well. */
-
-bool silc_idcache_del_all(SilcIDCache cache)
-{
-  silc_hash_table_free(cache->id_table);
-  silc_hash_table_free(cache->name_table);
-  silc_hash_table_free(cache->context_table);
-
-  return TRUE;
-}
+/* Update entry */
 
-static void silc_idcache_destructor_dummy(void *key, void *context,
-                                         void *user_context)
+SilcBool silc_idcache_update(SilcIDCache cache, SilcIDCacheEntry entry,
+                            void *old_id, void *new_id,
+                            char *old_name, char *new_name)
 {
-  /* Dummy - nothing */
-}
+  if (old_id && new_id) {
+    if (!silc_hash_table_del_by_context(cache->id_table, old_id, entry))
+      return FALSE;
 
-/* Foreach callback fro silc_idcache_purge. */
+    entry->id = new_id;
 
-static void silc_idcache_purge_foreach(void *key, void *context,
-                                      void *user_context)
-{
-  SilcIDCache cache = (SilcIDCache)user_context;
-  SilcUInt32 curtime = time(NULL);
-  SilcIDCacheEntry c = (SilcIDCacheEntry)context;
-  bool ret = FALSE;
-
-  if (!context)
-    return;
-
-  if (c->expire && c->expire < curtime) {
-    /* Remove the entry from the hash tables */
-    if (c->name)
-      ret = silc_hash_table_del_by_context(cache->name_table, c->name, c);
-    if (c->context)
-      ret = silc_hash_table_del(cache->context_table, c->context);
-    if (c->id)
-      ret =
-       silc_hash_table_del_by_context_ext(cache->id_table, c->id, c,
-                                          NULL, NULL, NULL, NULL,
-                                          silc_idcache_destructor_dummy,
-                                          NULL);
-    if (ret == TRUE) {
-      /* Call the destructor */
-      if (cache->destructor)
-       cache->destructor(cache, c, cache->context);
-
-      /* Free the entry, it has been deleted from the hash tables */
-      silc_idcache_destructor(NULL, c, NULL);
-    }
+    if (!silc_hash_table_add(cache->id_table, entry->id, entry))
+      return FALSE;
   }
-}
-
-/* Purges the cache by removing expired cache entires. Note that this
-   may be very slow operation. */
-
-bool silc_idcache_purge(SilcIDCache cache)
-{
-  silc_hash_table_foreach(cache->id_table, silc_idcache_purge_foreach, cache);
-  return TRUE;
-}
 
-/* Purges the specific entry by context. */
+  if (old_name && new_name) {
+    if (!silc_hash_table_del_by_context(cache->name_table, old_name, entry))
+      return FALSE;
 
-bool silc_idcache_purge_by_context(SilcIDCache cache, void *context)
-{
-  SilcIDCacheEntry c;
-  bool ret = FALSE;
-
-  if (!silc_hash_table_find(cache->context_table, context, NULL,
-                           (void *)&c))
-    return FALSE;
+    entry->name = new_name;
 
-    /* Remove the entry from the hash tables */
-  if (c->name)
-    ret = silc_hash_table_del_by_context(cache->name_table, c->name, c);
-  if (c->context)
-    ret = silc_hash_table_del(cache->context_table, c->context);
-  if (c->id)
-    ret =
-      silc_hash_table_del_by_context_ext(cache->id_table, c->id, c,
-                                        NULL, NULL, NULL, NULL,
-                                        silc_idcache_destructor_dummy, NULL);
-  if (ret == TRUE) {
-    /* Call the destructor */
-    if (cache->destructor)
-      cache->destructor(cache, c, cache->context);
-
-    /* Free the entry, it has been deleted from the hash tables */
-    silc_idcache_destructor(NULL, c, NULL);
+    if (!silc_hash_table_add(cache->name_table, entry->name, entry))
+      return FALSE;
   }
 
-  return ret;
-}
-
-/* Callback that is called by the hash table routine when traversing
-   entrys in the hash table. */
-
-static void silc_idcache_get_all_foreach(void *key, void *context,
-                                        void *user_context)
-{
-  SilcIDCacheList list = (SilcIDCacheList)user_context;
-  if (!context)
-    return;
-  silc_idcache_list_add(list, (SilcIDCacheEntry)context);
+  return TRUE;
 }
 
 /* Returns all cache entrys from the ID cache to the `ret' ID Cache List. */
 
-bool silc_idcache_get_all(SilcIDCache cache, SilcIDCacheList *ret)
+SilcBool silc_idcache_get_all(SilcIDCache cache, SilcList *ret_list)
 {
-  SilcIDCacheList list;
-
-  if (!ret)
-    return TRUE;
-
-  list = silc_idcache_list_alloc();
-  if (!list)
+  if (!ret_list)
     return FALSE;
-  silc_hash_table_foreach(cache->id_table, silc_idcache_get_all_foreach, list);
 
-  if (silc_idcache_list_count(list) == 0) {
-    silc_idcache_list_free(list);
+  if (!silc_hash_table_count(cache->id_table))
     return FALSE;
-  }
 
-  *ret = list;
+  silc_hash_table_foreach(cache->id_table, silc_idcache_get_all_foreach,
+                         ret_list);
+
+  if (!silc_list_count(*ret_list))
+    return FALSE;
 
   return TRUE;
 }
 
 /* Find ID Cache entry by ID. May return multiple entries. */
 
-bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
-                            SilcIDCacheList *ret)
+SilcBool silc_idcache_find_by_id(SilcIDCache cache, void *id,
+                                SilcList *ret_list)
 {
-  SilcIDCacheList list;
-
-  list = silc_idcache_list_alloc();
-  if (!list)
+  if (!ret_list)
     return FALSE;
 
-  if (!ret)
-    return TRUE;
+  if (!silc_hash_table_count(cache->id_table))
+    return FALSE;
 
   silc_hash_table_find_foreach(cache->id_table, id,
-                              silc_idcache_get_all_foreach, list);
+                              silc_idcache_get_all_foreach, ret_list);
 
-  if (silc_idcache_list_count(list) == 0) {
-    silc_idcache_list_free(list);
+  if (!silc_list_count(*ret_list))
     return FALSE;
-  }
-
-  *ret = list;
 
   return TRUE;
 }
 
-/* Find specific ID with specific hash function and comparison functions.
-   If `hash' is NULL then the default hash funtion is used and if `compare'
-   is NULL default comparison function is used. */
+/* Find one specific ID entry.  Compare full IDs */
 
-bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
-                                    SilcHashFunction hash,
-                                    void *hash_context,
-                                    SilcHashCompare compare,
-                                    void *compare_context,
+SilcBool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
                                     SilcIDCacheEntry *ret)
 {
   return silc_hash_table_find_ext(cache->id_table, id, NULL, (void *)ret,
-                                 hash, hash_context, compare,
-                                 compare_context);
-}
-
-/* Find one specific ID entry. */
-
-bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
-                                SilcIDCacheEntry *ret)
-{
-  return silc_hash_table_find(cache->id_table, id, NULL, (void *)ret);
+                                 NULL, NULL,
+                                 silc_hash_id_compare_full,
+                                 SILC_32_TO_PTR(cache->id_type));
 }
 
 /* Finds cache entry by context. */
 
-bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
-                                 SilcIDCacheEntry *ret)
+SilcBool silc_idcache_find_by_context(SilcIDCache cache, void *context,
+                                     SilcIDCacheEntry *ret)
 {
   return silc_hash_table_find(cache->context_table, context, NULL,
                              (void *)ret);
@@ -494,161 +309,28 @@ bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
 
 /* Find ID Cache entry by name. Returns list of cache entries. */
 
-bool silc_idcache_find_by_name(SilcIDCache cache, char *name,
-                              SilcIDCacheList *ret)
+SilcBool silc_idcache_find_by_name(SilcIDCache cache, char *name,
+                                  SilcList *ret_list)
 {
-  SilcIDCacheList list;
-
-  list = silc_idcache_list_alloc();
-  if (!list)
+  if (!ret_list)
     return FALSE;
 
-  if (!ret)
-    return TRUE;
+  if (!silc_hash_table_count(cache->name_table))
+    return FALSE;
 
   silc_hash_table_find_foreach(cache->name_table, name,
-                              silc_idcache_get_all_foreach, list);
+                              silc_idcache_get_all_foreach, ret_list);
 
-  if (silc_idcache_list_count(list) == 0) {
-    silc_idcache_list_free(list);
+  if (!silc_list_count(*ret_list))
     return FALSE;
-  }
-
-  *ret = list;
 
   return TRUE;
 }
 
 /* Find ID Cache entry by name. Returns one cache entry. */
 
-bool silc_idcache_find_by_name_one(SilcIDCache cache, char *name,
-                                  SilcIDCacheEntry *ret)
+SilcBool silc_idcache_find_by_name_one(SilcIDCache cache, char *name,
+                                      SilcIDCacheEntry *ret)
 {
-  if (!silc_hash_table_find(cache->name_table, name, NULL, (void *)ret))
-    return FALSE;
-
-  return TRUE;
-}
-
-/* Allocates ID cache list. */
-
-static SilcIDCacheList silc_idcache_list_alloc()
-{
-  SilcIDCacheList list;
-
-  list = silc_calloc(1, sizeof(*list));
-  if (!list)
-    return FALSE;
-
-  return list;
-}
-
-/* Adds cache entry to the ID cache list. If needed reallocates memory
-   for the list. */
-
-static void silc_idcache_list_add(SilcIDCacheList list, SilcIDCacheEntry cache)
-{
-  int i;
-
-  /* Try to add to static cache */
-  if (!list->cache_dyn_count)
-    for (i = 0; i < (sizeof(list->cache) / sizeof(list->cache[0])); i++) {
-      if (!list->cache[i]) {
-       list->cache[i] = cache;
-       list->cache_count++;
-       return;
-      }
-    }
-
-  /* Static cache is full, allocate dynamic cache */
-  for (i = 0; i < list->cache_dyn_count; i++) {
-    if (!list->cache_dyn[i]) {
-      list->cache_dyn[i] = cache;
-      list->cache_count++;
-      break;
-    }
-  }
-
-  if (i >= list->cache_dyn_count) {
-    int k;
-
-    i = list->cache_dyn_count;
-    list->cache_dyn = silc_realloc(list->cache_dyn,
-                                  sizeof(*list->cache_dyn) * (i + 5));
-    if (!list->cache_dyn)
-      return;
-
-    /* NULL the reallocated area */
-    for (k = i; k < (i + 5); k++)
-      list->cache_dyn[k] = NULL;
-
-    list->cache_dyn[i] = cache;
-    list->cache_count++;
-    list->cache_dyn_count += 5;
-  }
-}
-
-/* Returns number of cache entries in the ID cache list. */
-
-int silc_idcache_list_count(SilcIDCacheList list)
-{
-  return list->cache_count;
-}
-
-/* Returns first entry from the ID cache list. */
-
-bool silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret)
-{
-  list->pos = 0;
-
-  if (!list->cache[list->pos])
-    return FALSE;
-
-  if (ret)
-    *ret = list->cache[list->pos];
-
-  return TRUE;
-}
-
-/* Returns next entry from the ID cache list. */
-
-bool silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret)
-{
-  list->pos++;
-
-  if (!list->dyn &&
-      list->pos >= (sizeof(list->cache) / sizeof(list->cache[0]))) {
-    list->pos = 0;
-    list->dyn = TRUE;
-  }
-
-  if (list->dyn && list->pos >= list->cache_dyn_count)
-    return FALSE;
-
-  if (!list->dyn && !list->cache[list->pos])
-    return FALSE;
-
-  if (list->dyn && !list->cache_dyn[list->pos])
-    return FALSE;
-
-  if (ret) {
-    if (!list->dyn)
-      *ret = list->cache[list->pos];
-    else
-      *ret = list->cache_dyn[list->pos];
-  }
-
-  return TRUE;
-}
-
-/* Frees ID cache list. User must free the list object returned by
-   any of the searching functions. */
-
-void silc_idcache_list_free(SilcIDCacheList list)
-{
-  if (list) {
-    if (list->cache_dyn)
-      silc_free(list->cache_dyn);
-    silc_free(list);
-  }
+  return silc_hash_table_find(cache->name_table, name, NULL, (void *)ret);
 }
index e445b0a4035e9bda852ef0893efd2e40a7fc60fc..c48fe0b6dd08daca75c9f00b7d0cf296ea11cd9c 100644 (file)
  *
  * NAME
  *
- *    typedef struct { ... } SilcIDCacheEntry;
+ *    typedef struct SilcIDCacheEntryStruct { ... } SilcIDCacheEntry;
  *
  * DESCRIPTION
  *
- *    This is one entry in the SILC ID Cache system. Contents of this is
- *    allocated outside the ID cache system, however, all the fields are
- *    filled with ID cache utility functions. The ID cache system does not
- *    allocate any of these fields nor free them.
- *
- *    void *id
- *
- *      The actual ID.
- *
- *    char name
- *
- *      A name associated with the ID.
- *
- *    SilcUInt32 expire
- *
- *      Time when this cache entry expires.  This is normal time() value
- *      plus the validity.  Cache entry has expired if current time is
- *      more than value in this field.  If this value is zero (0) the
- *      entry never expires.
- *
- *    void *context
- *
- *      Any caller specified context.
+ *    This is an entry in the SILC ID Cache system.  This context is
+ *    allocated by adding new entry to ID cache by calling silc_idcache_add.
+ *    Each of the fields in the structure are allocated by the caller.
  *
  * SOURCE
  */
-typedef struct {
-  void *id;
-  char *name;
-  SilcUInt32 expire;
-  void *context;
+typedef struct SilcIDCacheEntryStruct {
+  struct SilcIDCacheEntryStruct *next;
+  void *id;                           /* Associated ID */
+  char *name;                         /* Associated entry name */
+  void *context;                      /* Associated context */
 } *SilcIDCacheEntry;
 /***/
 
@@ -88,45 +68,26 @@ typedef struct {
  ***/
 typedef struct SilcIDCacheStruct *SilcIDCache;
 
-/****s* silccore/SilcIDCacheAPI/SilcIDCacheList
- *
- * NAME
- *
- *    typedef struct SilcIDCacheListStruct *SilcIDCacheList;
- *
- * DESCRIPTION
- *
- *    This context is the ID Cache List and is allocated by
- *    some of the silc_idcache_* functions. Functions that may return
- *    multiple entries from the cache allocate the entries in to the
- *    SilcIDCacheList. The context is freed by silc_idcache_list_free
- *    function.
- *
- ***/
-typedef struct SilcIDCacheListStruct *SilcIDCacheList;
-
 /****f* silccore/SilcIDCacheAPI/SilcIDCacheDestructor
  *
  * SYNOPSIS
  *
  *    typedef void (*SilcIDCacheDestructor)(SilcIDCache cache,
- *                                          SilcIDCacheEntry entry,
- *                                          void *context);
+ *                                          const SilcIDCacheEntry entry,
+ *                                          void *destructor_context,
+ *                                          void *app_context);
  *
  * DESCRIPTION
  *
- *    Destructor callback that is called when an cache entry expires or is
- *    purged from the ID cache. The application must not free cache entry
- *    because the library will do it automatically. The appliation, however,
- *    is responsible of freeing any data in the entry.
+ *    Destructor callback given as argument to silc_idcache_alloc.  This
+ *    is called when an entry is deleted from the cache.  Application
+ *    must free the contents of the `entry'.
  *
  ***/
 typedef void (*SilcIDCacheDestructor)(SilcIDCache cache,
-                                     SilcIDCacheEntry entry,
-                                     void *context);
-
-#define SILC_ID_CACHE_EXPIRE 3600
-#define SILC_ID_CACHE_EXPIRE_DEF (time(NULL) + SILC_ID_CACHE_EXPIRE)
+                                     const SilcIDCacheEntry entry,
+                                     void *destructor_context,
+                                     void *app_context);
 
 /* Prototypes */
 
@@ -137,7 +98,7 @@ typedef void (*SilcIDCacheDestructor)(SilcIDCache cache,
  *    SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
  *                                   SilcIDCacheDestructor destructor,
  *                                   void *destructor_context,
- *                                   bool delete_id, bool delete_name);
+ *                                   SilcBool delete_id, SilcBool delete_name);
  *
  * DESCRIPTION
  *
@@ -146,15 +107,10 @@ typedef void (*SilcIDCacheDestructor)(SilcIDCache cache,
  *    The `id_type' defines the types of the ID's that will be saved to the
  *    cache.
  *
- *    If 'delete_id' is TRUE then library will free the ID when a
- *    cache entry is deleted.  If 'delete_name' is TRUE then library
- *    will delete the associated name when a cache entry is deleted.
- *
  ***/
 SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
                               SilcIDCacheDestructor destructor,
-                              void *destructor_context,
-                              bool delete_id, bool delete_name);
+                              void *destructor_context);
 
 /****f* silccore/SilcIDCacheAPI/silc_idcache_free
  *
@@ -164,7 +120,7 @@ SilcIDCache silc_idcache_alloc(SilcUInt32 count, SilcIdType id_type,
  *
  * DESCRIPTION
  *
- *    Frees ID cache object and all cache entries.
+ *    Frees ID cache context and all cache entries.
  *
  ***/
 void silc_idcache_free(SilcIDCache cache);
@@ -173,219 +129,160 @@ void silc_idcache_free(SilcIDCache cache);
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
- *                          void *context, int expire, SilcIDCacheEntry *ret);
+ *    SilcIDCacheEntry
+ *    silc_idcache_add(SilcIDCache cache, char *name, void *id, void *context);
  *
  * DESCRIPTION
  *
- *    Add new entry to the cache. Returns TRUE if the entry was added and
- *    FALSE if it could not be added. The `name' is the name associated with
- *    the ID, the `id' the actual ID and the `context' a user specific context.
- *    If the `expire' is non-zero the entry expires in that specified time.
- *    If zero the entry never expires from the cache.
+ *    Add new entry to the cache.  Returns the allocated cache entry if the
+ *    entry was added successfully, or NULL if error occurred.  The `name' is
+ *    the name associated with the ID, the `id' the actual ID and the
+ *    `context' a caller specific context.
  *
- *    The `name', `id' and `context' pointers will be saved in the cache,
+ *    The `name', `id' and `context' pointers will be stored in the cache,
  *    and if the caller frees these pointers the caller is also responsible
- *    of deleting the cache entry.  Otherwise the cache will have the freed
- *    pointers stored.
- *
- *    If the `ret' is non-NULL the created ID Cache entry is returned to
- *    that pointer.
+ *    of deleting the cache entry.
  *
  ***/
-bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
-                     void *context, int expire, SilcIDCacheEntry *ret);
+SilcIDCacheEntry
+silc_idcache_add(SilcIDCache cache, char *name, void *id, void *context);
 
 /****f* silccore/SilcIDCacheAPI/silc_idcache_del
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old);
+ *    SilcBool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry entry,
+ *                              void *app_context);
  *
  * DESCRIPTION
  *
- *    Delete cache entry from cache. Returns TRUE if the entry was deleted.
- *    The destructor function is not called.
+ *    Delete cache entry from cache.  Returns TRUE if the entry was deleted.
+ *    The destructor will be called for the entry.  The `app_context' is
+ *    delivered to the destructor.
  *
  ***/
-bool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old);
+SilcBool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry entry,
+                         void *app_context);
 
 /****f* silccore/SilcIDCacheAPI/silc_idcache_del_by_id
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_del_by_id(SilcIDCache cache, void *id);
- *
- * DESCRIPTION
- *
- *    Delete cache entry by ID. Returns TRUE if the entry was deleted.
- *    The destructor function is not called.
- *
- ***/
-bool silc_idcache_del_by_id(SilcIDCache cache, void *id);
-
-/****f* silccore/SilcIDCacheAPI/silc_idcache_del_by_id_ext
- *
- * SYNOPSIS
- *
- *    bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
- *                                    SilcHashFunction hash,
- *                                    void *hash_context,
- *                                    SilcHashCompare compare,
- *                                    void *compare_context);
+ *    SilcBool silc_idcache_del_by_id(SilcIDCache cache, void *id,
+ *                                    void *app_context);
  *
  * DESCRIPTION
  *
- *    Same as silc_idcache_del_by_id but with specific hash and comparison
- *    functions. If the functions are NULL then default values are used.
- *    Returns TRUE if the entry was deleted. The destructor function is
- *    called.
+ *    Delete cache entry by ID.  Returns TRUE if the entry was deleted.
+ *    The destructor will be called for the entry.  The `app_context' is
+ *    delivered to the destructor.
  *
  ***/
-bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
-                               SilcHashFunction hash,
-                               void *hash_context,
-                               SilcHashCompare compare,
-                               void *compare_context);
+SilcBool silc_idcache_del_by_id(SilcIDCache cache, void *id,
+                               void *app_context);
 
 /****f* silccore/SilcIDCacheAPI/silc_idcache_del_by_context
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_del_by_context(SilcIDCache cache, void *context);
- *
- * DESCRIPTION
- *
- *    Deletes cachen entry by the user specified context. Returns TRUE
- *    if the entry was deleted. The destructor function is not called.
- *
- ***/
-bool silc_idcache_del_by_context(SilcIDCache cache, void *context);
-
-/****f* silccore/SilcIDCacheAPI/silc_idcache_del_all
- *
- * SYNOPSIS
- *
- *    bool silc_idcache_del_all(SilcIDCache cache);
- *
- * DESCRIPTION
- *
- *    Deletes all cache entries from the cache and frees all memory.
- *    The destructor function is not called.
- *
- ***/
-bool silc_idcache_del_all(SilcIDCache cache);
-
-/****f* silccore/SilcIDCacheAPI/silc_idcache_purge
- *
- * SYNOPSIS
- *
- *    bool silc_idcache_purge(SilcIDCache cache);
+ *    SilcBool silc_idcache_del_by_context(SilcIDCache cache, void *context);
  *
  * DESCRIPTION
  *
- *    Purges the cache by removing expired cache entires. Note that this
- *    may be very slow operation. Returns TRUE if the purging was successful.
- *    The destructor function is called for each purged cache entry.
+ *    Deletes cachen entry by the user specified context.  Returns TRUE
+ *    if the entry was deleted.  The destructor will be called for the
+ *    entry.  The `app_context' is delivered to the destructor.
  *
  ***/
-bool silc_idcache_purge(SilcIDCache cache);
+SilcBool silc_idcache_del_by_context(SilcIDCache cache, void *context,
+                                    void *app_context);
 
-/****f* silccore/SilcIDCacheAPI/silc_idcache_by_context
+/****f* silccore/SilcIDCacheAPI/silc_idcache_update_id
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_purge_by_context(SilcIDCache cache, void *context);
+ *    SilcBool silc_idcache_update(SilcIDCache cache, SilcIDCacheEntry entry,
+ *                                 void *old_id, void *new_id,
+ *                                 char *old_name, char *new_name);
  *
  * DESCRIPTION
  *
- *    Purges the cache by context and removes expired cache entires.
- *    Returns TRUE if the puring was successful. The destructor function
- *    is called for the purged cache entry.
+ *    Updates cache `entry' with new values.  If the `new_id' is non-NULL
+ *    then the `entry' will be updated with `new_id'.  If the `new_name' is
+ *    non-NULL then the `entry' will be updated with `new_name'.  The
+ *    caller is responsible of freeing the old values that was added with
+ *    silc_idcache_add.
  *
  ***/
-bool silc_idcache_purge_by_context(SilcIDCache cache, void *context);
+SilcBool silc_idcache_update(SilcIDCache cache, SilcIDCacheEntry entry,
+                            void *old_id, void *new_id,
+                            char *old_name, char *new_name);
 
 /****f* silccore/SilcIDCacheAPI/silc_idcache_get_all
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_get_all(SilcIDCache cache, SilcIDCacheList *ret);
+ *    SilcBool silc_idcache_get_all(SilcIDCache cache, SilcList *ret_list);
  *
  * DESCRIPTION
  *
- *    Returns all cache entries from the ID cache to the `ret' SilcIDCacheList.
- *    Returns TRUE if the retrieval was successful. The caller must free
- *    the returned SilcIDCacheList.
+ *    Returns all cache entries into the SilcList `ret_list' pointer.  Each
+ *    entry in the list is SilcIDCacheEntry.  Returns FALSE if the cache
+ *    is empty.
  *
  ***/
-bool silc_idcache_get_all(SilcIDCache cache, SilcIDCacheList *ret);
+SilcBool silc_idcache_get_all(SilcIDCache cache, SilcList *ret_list);
 
 /****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_id
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
- *                                 SilcIDCacheList *ret);
+ *    SilcBool silc_idcache_find_by_id(SilcIDCache cache, void *id,
+ *                                     SilcList *ret_list);
  *
  * DESCRIPTION
  *
- *    Find ID Cache entry by ID. This may return multiple entry and the
- *    `ret' SilcIDCacheList is allocated. Returns TRUE if the entry was
- *    found. The caller must free the returned SilcIDCacheList.
- *
- ***/
-bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
-                            SilcIDCacheList *ret);
-
-/****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_id_one
+ *    Find ID Cache entry by ID.  This may return multiple entries.
+ *    The entires are returned into the `ret_list' SilcList context.
+ *    Returns TRUE if entry was found.
  *
- * SYNOPSIS
- *
- *     bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
- *                                      SilcIDCacheEntry *ret);
+ * NOTES
  *
- * DESCRIPTION
+ *    If this function is used to find Client ID (SilcClientID), only the
+ *    hash portion of the Client ID is compared.  Use the function
+ *    silc_idcache_find_by_id_one to find exact match for Client ID (full
+ *    ID is compared and not only the hash).
  *
- *    Find ID Cache entry by ID. Returns only one entry from the cache
- *    and the found entry is considered to be exact match. Returns TRUE
- *    if the entry was found.
+ *    Comparing only the hash portion of Client ID allows searching of
+ *    Client ID's by nickname, because the hash is based on the nickname.
+ *    As nicknames are not unique, multiple entries may be found.
  *
  ***/
-bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
-                                SilcIDCacheEntry *ret);
+SilcBool silc_idcache_find_by_id(SilcIDCache cache, void *id,
+                                SilcList *ret_list);
 
-/****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_id_one_ext
+/****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_id_one
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
- *                                         SilcHashFunction hash,
- *                                         void *hash_context,
- *                                         SilcHashCompare compare,
- *                                         void *compare_context,
- *                                         SilcIDCacheEntry *ret);
+ *     SilcBool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
+ *                                          SilcIDCacheEntry *ret);
  *
  * DESCRIPTION
  *
- *    Same as silc_idcache_find_by_id_one but with specific hash and
- *    comparison functions. If `hash' is NULL then the default hash
- *    funtion is used and if `compare' is NULL default comparison function
- *    is used. Returns TRUE if the entry was found.
+ *    Find ID Cache entry by ID.  Returns only one entry from the cache
+ *    and the found entry is considered to be exact match.  Returns TRUE
+ *    if the entry was found.
  *
  ***/
-bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
-                                    SilcHashFunction hash,
-                                    void *hash_context,
-                                    SilcHashCompare compare,
-                                    void *compare_context,
+SilcBool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
                                     SilcIDCacheEntry *ret);
 
 /****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_context
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
+ *    SilcBool silc_idcache_find_by_context(SilcIDCache cache, void *context,
  *                                      SilcIDCacheEntry *ret);
  *
  * DESCRIPTION
@@ -394,98 +291,41 @@ bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
  *    entry was found.
  *
  ***/
-bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
-                                 SilcIDCacheEntry *ret);
+SilcBool silc_idcache_find_by_context(SilcIDCache cache, void *context,
+                                     SilcIDCacheEntry *ret);
 
 /****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_name
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_find_by_name(SilcIDCache cache, char *name,
- *                                   SilcIDCacheList *ret);
+ *    SilcBool silc_idcache_find_by_name(SilcIDCache cache, char *name,
+ *                                       SilcList *ret_list);
  *
  * DESCRIPTION
  *
- *    Find cache entries by the name associated with the ID. This may
- *    return muliptle entries allocated to the SilcIDCacheList. Returns
- *    TRUE if the entry was found. The caller must free the SIlcIDCacheList.
+ *    Find cache entries by the name associated with the ID.  This may
+ *    return multiple entries to the `ret_list' SilcList context.  Returns
+ *    TRUE if the entry was found.
  *
  ***/
-bool silc_idcache_find_by_name(SilcIDCache cache, char *name,
-                              SilcIDCacheList *ret);
+SilcBool silc_idcache_find_by_name(SilcIDCache cache, char *name,
+                                  SilcList *ret_list);
 
 /****f* silccore/SilcIDCacheAPI/silc_idcache_find_by_name_one
  *
  * SYNOPSIS
  *
- *    bool silc_idcache_find_by_name_one(SilcIDCache cache, char *name,
+ *    SilcBool silc_idcache_find_by_name_one(SilcIDCache cache, char *name,
  *                                       SilcIDCacheEntry *ret);
  *
  * DESCRIPTION
  *
- *    Find cache entry by the name associated with the ID. This returns
+ *    Find cache entry by the name associated with the ID.  This returns
  *    one entry and the found entry is considered to be exact match.
- *    return muliptle entries allocated to the SilcIDCacheList. Returns
- *    TRUE if the entry was found.
- *
- ***/
-bool silc_idcache_find_by_name_one(SilcIDCache cache, char *name,
-                                  SilcIDCacheEntry *ret);
-
-/****f* silccore/SilcIDCacheAPI/silc_idcache_list_count
- *
- * SYNOPSIS
- *
- *    int silc_idcache_list_count(SilcIDCacheList list);
- *
- * DESCRIPTION
- *
- *    Returns the number of cache entries in the ID cache list.
- *
- ***/
-int silc_idcache_list_count(SilcIDCacheList list);
-
-/****f* silccore/SilcIDCacheAPI/silc_idcache_list_first
- *
- * SYNOPSIS
- *
- *    bool silc_idcache_list_first(SilcIDCacheList list,
- *                                 SilcIDCacheEntry *ret);
- *
- * DESCRIPTION
- *
- *    Returns the first cache entry from the ID cache list. Returns FALSE
- *    If the entry could not be retrieved.
- *
- ***/
-bool silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret);
-
-/****f* silccore/SilcIDCacheAPI/silc_idcache_list_next
- *
- * SYNOPSIS
- *
- *    bool silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret);
- *
- * DESCRIPTION
- *
- *    Returns the next cache entry from the ID Cache list. Returns FALSE
- *    when there are not anymore entries in the list.
- *
- ***/
-bool silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret);
-
-/****f* silccore/SilcIDCacheAPI/silc_idcache_list_free
- *
- * SYNOPSIS
- *
- *    void silc_idcache_list_free(SilcIDCacheList list);
- *
- * DESCRIPTION
- *
- *     Frees ID cache list. User must free the list context returned by
- *     any of the searching functions.
+ *    Returns TRUE if the entry was found.
  *
  ***/
-void silc_idcache_list_free(SilcIDCacheList list);
+SilcBool silc_idcache_find_by_name_one(SilcIDCache cache, char *name,
+                                      SilcIDCacheEntry *ret);
 
-#endif
+#endif /* SILCIDCACHE_H */
index d46a4148ad66472f3d5c5633e4246cf7d046b52f..cf4ee1bf674a05783d0bcb7d053a156559552ca3 100644 (file)
@@ -20,7 +20,7 @@
    private messages. */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcmessage.h"
 
 /******************************************************************************
@@ -59,13 +59,13 @@ struct SilcMessagePayloadStruct {
 
 /* Decrypts the Message Payload. The `data' is the actual Message Payload */
 
-bool silc_message_payload_decrypt(unsigned char *data,
+SilcBool silc_message_payload_decrypt(unsigned char *data,
                                  size_t data_len,
-                                 bool private_message,
-                                 bool static_key,
+                                 SilcBool private_message,
+                                 SilcBool static_key,
                                  SilcCipher cipher,
                                  SilcHmac hmac,
-                                 bool check_mac)
+                                 SilcBool check_mac)
 {
   SilcUInt32 mac_len, iv_len = 0, block_len;
   SilcUInt16 len, totlen, dlen;
@@ -148,8 +148,8 @@ bool silc_message_payload_decrypt(unsigned char *data,
 SilcMessagePayload
 silc_message_payload_parse(unsigned char *payload,
                           SilcUInt32 payload_len,
-                          bool private_message,
-                          bool static_key,
+                          SilcBool private_message,
+                          SilcBool static_key,
                           SilcCipher cipher,
                           SilcHmac hmac)
 {
@@ -229,7 +229,7 @@ silc_message_payload_parse(unsigned char *payload,
    Payload encoding routines but application may call this too if needed.
    The `true_len' is the data length which is used to create MAC out of. */
 
-bool silc_message_payload_encrypt(unsigned char *data,
+SilcBool silc_message_payload_encrypt(unsigned char *data,
                                  SilcUInt32 data_len,
                                  SilcUInt32 true_len,
                                  unsigned char *iv,
@@ -263,8 +263,8 @@ bool silc_message_payload_encrypt(unsigned char *data,
 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
                                       const unsigned char *data,
                                       SilcUInt32 data_len,
-                                      bool generate_iv,
-                                      bool private_message,
+                                      SilcBool generate_iv,
+                                      SilcBool private_message,
                                       SilcCipher cipher,
                                       SilcHmac hmac,
                                       SilcRng rng,
@@ -571,7 +571,7 @@ silc_message_signed_payload_encode(const unsigned char *message_payload,
   /* Sign the buffer */
 
   /* Allocate PKCS object */
-  if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
+  if (!silc_pkcs_alloc(private_key->name, SILC_PKCS_SILC, &pkcs)) {
     SILC_LOG_ERROR(("Could not allocated PKCS"));
     silc_buffer_clear(sign);
     silc_buffer_free(sign);
@@ -679,7 +679,7 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig,
     return ret;
 
   /* Allocate PKCS object */
-  if (!silc_pkcs_alloc(remote_public_key->name, &pkcs)) {
+  if (!silc_pkcs_alloc(remote_public_key->name, SILC_PKCS_SILC, &pkcs)) {
     silc_buffer_clear(sign);
     silc_buffer_free(sign);
     return ret;
index 32e40c93498ce3f8582ad6fb4acc5142ff0dd16d..7dc136efeca6905d369e058764ff5aadc86c6d46 100644 (file)
@@ -105,13 +105,13 @@ typedef SilcUInt16 SilcMessageFlags;
  *
  * SYNOPSIS
  *
- *    bool silc_message_payload_decrypt(unsigned char *data,
+ *    SilcBool silc_message_payload_decrypt(unsigned char *data,
  *                                      size_t data_len,
- *                                      bool private_message,
- *                                      bool static_key,
+ *                                      SilcBool private_message,
+ *                                      SilcBool static_key,
  *                                      SilcCipher cipher,
  *                                      SilcHmac hmac,
- *                                      bool check_mac);
+ *                                      SilcBool check_mac);
  *
  * DESCRIPTION
  *
@@ -130,13 +130,13 @@ typedef SilcUInt16 SilcMessageFlags;
  *    `check_mac' is FALSE then MAC is not verified.
  *
  ***/
-bool silc_message_payload_decrypt(unsigned char *data,
+SilcBool silc_message_payload_decrypt(unsigned char *data,
                                  size_t data_len,
-                                 bool private_message,
-                                 bool static_key,
+                                 SilcBool private_message,
+                                 SilcBool static_key,
                                  SilcCipher cipher,
                                  SilcHmac hmac,
-                                 bool check_mac);
+                                 SilcBool check_mac);
 
 /****f* silccore/SilcMessageAPI/silc_message_payload_parse
  *
@@ -145,8 +145,8 @@ bool silc_message_payload_decrypt(unsigned char *data,
  *    SilcMessagePayload 
  *    silc_message_payload_parse(unsigned char *payload,
  *                               SilcUInt32 payload_len,
- *                               bool private_message,
- *                               bool static_key,
+ *                               SilcBool private_message,
+ *                               SilcBool static_key,
  *                               SilcCipher cipher,
  *                               SilcHmac hmac);
  *
@@ -170,8 +170,8 @@ bool silc_message_payload_decrypt(unsigned char *data,
 SilcMessagePayload 
 silc_message_payload_parse(unsigned char *payload,
                           SilcUInt32 payload_len,
-                          bool private_message,
-                          bool static_key,
+                          SilcBool private_message,
+                          SilcBool static_key,
                           SilcCipher cipher,
                           SilcHmac hmac);
 
@@ -179,7 +179,7 @@ silc_message_payload_parse(unsigned char *payload,
  *
  * SYNOPSIS
  *
- *    bool silc_message_payload_encrypt(unsigned char *data,
+ *    SilcBool silc_message_payload_encrypt(unsigned char *data,
  *                                      SilcUInt32 data_len,
  *                                      SilcUInt32 true_len,
  *                                      unsigned char *iv,
@@ -201,7 +201,7 @@ silc_message_payload_parse(unsigned char *payload,
  *    to compute the MAC for the payload.
  *
  ***/
-bool silc_message_payload_encrypt(unsigned char *data,
+SilcBool silc_message_payload_encrypt(unsigned char *data,
                                  SilcUInt32 data_len,
                                  SilcUInt32 true_len,
                                  unsigned char *iv,
@@ -216,8 +216,8 @@ bool silc_message_payload_encrypt(unsigned char *data,
  *    SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
  *                                           const unsigned char *data,
  *                                           SilcUInt32 data_len,
- *                                           bool generate_iv,
- *                                           bool private_message,
+ *                                           SilcBool generate_iv,
+ *                                           SilcBool private_message,
  *                                           SilcCipher cipher,
  *                                           SilcHmac hmac,
  *                                           SilcRng rng,
@@ -257,8 +257,8 @@ bool silc_message_payload_encrypt(unsigned char *data,
 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
                                       const unsigned char *data,
                                       SilcUInt32 data_len,
-                                      bool generate_iv,
-                                      bool private_message,
+                                      SilcBool generate_iv,
+                                      SilcBool private_message,
                                       SilcCipher cipher,
                                       SilcHmac hmac,
                                       SilcRng rng,
index 86a2a1be3cada203cbe39cddd885385dc1cad5f4..ec61e78a3e49a3e86f660982bcf534c168aa8806 100644 (file)
@@ -1,15 +1,15 @@
 /*
+
   silcmode.h
+
   Author: Pekka Riikonen <priikone@silcnet.org>
-  
+
   Copyright (C) 2001 - 2005 Pekka Riikonen
-  
+
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.
+
   This program 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
  *
  * SOURCE
  */
-#define SILC_CHANNEL_MODE_NONE         0x0000
-#define SILC_CHANNEL_MODE_PRIVATE      0x0001 /* private channel */
-#define SILC_CHANNEL_MODE_SECRET       0x0002 /* secret channel */
-#define SILC_CHANNEL_MODE_PRIVKEY      0x0004 /* channel has private key */
-#define SILC_CHANNEL_MODE_INVITE       0x0008 /* invite only channel */
-#define SILC_CHANNEL_MODE_TOPIC        0x0010 /* topic setting by operator */
-#define SILC_CHANNEL_MODE_ULIMIT       0x0020 /* user limit set */
-#define SILC_CHANNEL_MODE_PASSPHRASE   0x0040 /* passphrase set */
-#define SILC_CHANNEL_MODE_CIPHER       0x0080 /* sets cipher of the channel */
-#define SILC_CHANNEL_MODE_HMAC         0x0100 /* sets hmac of the channel */
-#define SILC_CHANNEL_MODE_FOUNDER_AUTH 0x0200 /* sets founder auth data */
+#define SILC_CHANNEL_MODE_NONE          0x0000
+#define SILC_CHANNEL_MODE_PRIVATE       0x0001 /* private channel */
+#define SILC_CHANNEL_MODE_SECRET        0x0002 /* secret channel */
+#define SILC_CHANNEL_MODE_PRIVKEY       0x0004 /* channel has private key */
+#define SILC_CHANNEL_MODE_INVITE        0x0008 /* invite only channel */
+#define SILC_CHANNEL_MODE_TOPIC         0x0010 /* topic setting by operator */
+#define SILC_CHANNEL_MODE_ULIMIT        0x0020 /* user limit set */
+#define SILC_CHANNEL_MODE_PASSPHRASE    0x0040 /* passphrase set */
+#define SILC_CHANNEL_MODE_CIPHER        0x0080 /* sets cipher of the channel */
+#define SILC_CHANNEL_MODE_HMAC          0x0100 /* sets hmac of the channel */
+#define SILC_CHANNEL_MODE_FOUNDER_AUTH  0x0200 /* sets founder auth data */
 #define SILC_CHANNEL_MODE_SILENCE_USERS 0x0400 /* sets founder auth data */
 #define SILC_CHANNEL_MODE_SILENCE_OPERS 0x0800 /* sets founder auth data */
-#define SILC_CHANNEL_MODE_CHANNEL_AUTH 0x1000 /* channel auth (signature) */
+#define SILC_CHANNEL_MODE_CHANNEL_AUTH  0x1000 /* channel auth (signature) */
 /***/
 
 /****d* silccore/Modes/ChannelUserModes
index 96f7fc39ce1b794635d28a483c431d2e1d0ffa6c..4f6feacbda0a14c42aaff2f1d3c0dc8196b7fd1e 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcnotify.h"
 
 /******************************************************************************
index 070662f290503847125c13c4ddd06995c72ab4bf..bea26e774325834672e75954eea541a102513517 100644 (file)
  */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
+
+/************************** Types and definitions ***************************/
 
 /* Packet engine */
 struct SilcPacketEngineStruct {
-  SilcSchedule schedule;                /* Application's scheduler */
   SilcRng rng;                          /* RNG for engine */
   SilcPacketCallbacks *callbacks;       /* Packet callbacks */
   void *callback_context;               /* Context for callbacks */
-  SilcDList streams;                    /* All streams in engine */
+  SilcList streams;                     /* All streams in engine */
   SilcList packet_pool;                 /* Free list for received packets */
   SilcMutex lock;                       /* Engine lock */
-  bool local_is_router;
+  SilcBool local_is_router;
 };
 
+/* Packet procesor context */
+typedef struct SilcPacketProcessStruct {
+  SilcInt32 priority;                   /* Priority */
+  SilcPacketType *types;                /* Packets to process */
+  SilcPacketCallbacks *callbacks;       /* Callbacks or NULL */
+  void *callback_context;
+} *SilcPacketProcess;
+
 /* Packet stream */
 struct SilcPacketStreamStruct {
+  struct SilcPacketStreamStruct *next;
   SilcPacketEngine engine;              /* Packet engine */
   SilcStream stream;                    /* Underlaying stream */
+  SilcMutex lock;                       /* Stream lock */
+  SilcDList process;                    /* Packet processors, it set */
   SilcHashTable streamers;              /* Valid if streamers exist */
-  void *app_context;                    /* Applicationn context */
-  SilcPacketCallbacks *callbacks;       /* Callbacks or NULL */
-  void *callback_context;
+  void *stream_context;                         /* Stream context */
   SilcBufferStruct inbuf;               /* In buffer */
   SilcBufferStruct outbuf;              /* Out buffer */
   SilcUInt32 send_psn;                  /* Sending sequence */
@@ -58,6 +68,8 @@ struct SilcPacketStreamStruct {
   unsigned int dst_id_len  : 6;
   unsigned int dst_id_type : 2;
   SilcUInt8 refcnt;                     /* Reference counter */
+  unsigned int is_router   : 1;                 /* Set if router stream */
+  unsigned int destroyed   : 1;                 /* Set if destroyed */
 };
 
 /* Initial size of stream buffers */
@@ -117,54 +129,190 @@ do {                                                                        \
              ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
 } while(0)
 
-static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
-                                 void *context);
-
-/* Receive packet callback */
-#define SILC_PACKET_CALLBACK_PACKET(s, p)                              \
-do {                                                                   \
-  if ((s)->callbacks && (s)->callbacks->packet_receive)                        \
-    (s)->callbacks->packet_receive((s)->engine, s, p,                  \
-                                  (s)->callback_context,               \
-                                  (s)->app_context);                   \
-  else                                                                 \
-    (s)->engine->callbacks->packet_receive((s)->engine, s, p,          \
-                                          (s)->callback_context,       \
-                                          (s)->app_context);           \
-} while(0)
-
 /* EOS callback */
 #define SILC_PACKET_CALLBACK_EOS(s)                                    \
 do {                                                                   \
-  if ((s)->callbacks && (s)->callbacks->eos)                           \
-    (s)->callbacks->eos((s)->engine, stream, (s)->callback_context,    \
-                       (s)->app_context);                              \
-  else                                                                 \
-    (s)->engine->callbacks->eos((s)->engine, s,                                \
-                               (s)->callback_context,                  \
-                               (s)->app_context);                      \
+  (s)->engine->callbacks->eos((s)->engine, s,                          \
+                             (s)->engine->callback_context,            \
+                             (s)->stream_context);                     \
 } while(0)
 
 /* Error callback */
 #define SILC_PACKET_CALLBACK_ERROR(s, err)                             \
 do {                                                                   \
-  if ((s)->callbacks && (s)->callbacks->error)                         \
-    (s)->callbacks->error((s)->engine, s, err, (s)->callback_context,  \
-                         (s)->app_context);                            \
-  else                                                                 \
-    (s)->engine->callbacks->error((s)->engine, s, err,                 \
-                                 (s)->callback_context,                \
-                                 (s)->app_context);                    \
+  (s)->engine->callbacks->error((s)->engine, s, err,                   \
+                               (s)->engine->callback_context,          \
+                               (s)->stream_context);                   \
 } while(0)
 
-static SilcPacket silc_packet_alloc(SilcPacketEngine engine);
+
+/************************ Static utility functions **************************/
+
 static void silc_packet_read_process(SilcPacketStream stream);
 
+/* Our stream IO notifier callback. */
+
+static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
+                                 void *context)
+{
+  SilcPacketStream ps = context;
+  int ret;
+
+  silc_mutex_lock(ps->lock);
+
+  if (ps->destroyed) {
+    silc_mutex_unlock(ps->lock);
+    return;
+  }
+
+  switch (status) {
+
+  case SILC_STREAM_CAN_WRITE:
+    if (!silc_buffer_headlen(&ps->outbuf)) {
+      silc_mutex_unlock(ps->lock);
+      return;
+    }
+
+    SILC_LOG_DEBUG(("Writing pending data to stream"));
+
+    /* Write pending data to stream */
+    while (silc_buffer_len(&ps->outbuf) > 0) {
+      ret = silc_stream_write(ps->stream, ps->outbuf.data,
+                             silc_buffer_len(&ps->outbuf));
+      if (ret == 0) {
+       /* EOS */
+       silc_buffer_reset(&ps->outbuf);
+       silc_mutex_unlock(ps->lock);
+       SILC_PACKET_CALLBACK_EOS(ps);
+       return;
+      }
+
+      if (ret == -2) {
+       /* Error */
+       silc_buffer_reset(&ps->outbuf);
+       silc_mutex_unlock(ps->lock);
+       SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
+       return;
+      }
+
+      if (ret == -1) {
+       /* Cannot write now, write later. */
+       silc_mutex_unlock(ps->lock);
+       return;
+      }
+
+      /* Wrote data */
+      silc_buffer_pull(&ps->outbuf, ret);
+    }
+
+    silc_buffer_reset(&ps->outbuf);
+
+    silc_mutex_unlock(ps->lock);
+    break;
+
+  case SILC_STREAM_CAN_READ:
+    /* Packet receiving can only happen in one thread, so locking is not
+       required in packet receiving procedure. */
+    silc_mutex_unlock(ps->lock);
+
+    SILC_LOG_DEBUG(("Reading data from stream"));
+
+    /* Make sure we have fair amount of free space in inbuf */
+    if (silc_buffer_taillen(&ps->inbuf) < SILC_PACKET_DEFAULT_SIZE)
+      if (!silc_buffer_realloc(&ps->inbuf, silc_buffer_truelen(&ps->inbuf) +
+                              SILC_PACKET_DEFAULT_SIZE * 2))
+       return;
+
+    /* Read data from stream */
+    ret = silc_stream_read(ps->stream, ps->inbuf.tail,
+                          silc_buffer_taillen(&ps->inbuf));
+
+    if (ret == 0) {
+      /* EOS */
+      silc_buffer_reset(&ps->inbuf);
+      SILC_PACKET_CALLBACK_EOS(ps);
+      return;
+    }
+
+    if (ret == -2) {
+      /* Error */
+      silc_buffer_reset(&ps->inbuf);
+      SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
+      return;
+    }
+
+    if (ret == -1) {
+      /* Cannot read now, do it later. */
+      silc_buffer_pull(&ps->inbuf, silc_buffer_len(&ps->inbuf));
+      return;
+    }
+
+    /* Read some data */
+    silc_buffer_pull_tail(&ps->inbuf, ret);
+
+    /* Now process the data */
+    silc_packet_read_process(ps);
+
+    break;
+
+  default:
+    silc_mutex_unlock(ps->lock);
+    break;
+  }
+}
+
+/* Allocate packet */
+
+static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
+{
+  SilcPacket packet;
+
+  SILC_LOG_DEBUG(("Packet pool count %d",
+                 silc_list_count(engine->packet_pool)));
+
+  silc_mutex_lock(engine->lock);
+
+  /* Get packet from freelist or allocate new one. */
+  packet = silc_list_get(engine->packet_pool);
+  if (!packet) {
+    void *tmp;
+
+    silc_mutex_unlock(engine->lock);
+
+    packet = silc_calloc(1, sizeof(*packet));
+    if (!packet)
+      return NULL;
+
+    SILC_LOG_DEBUG(("Allocating new packet %p", packet));
+
+    tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
+    if (!tmp) {
+      silc_free(packet);
+      return NULL;
+    }
+    silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
+    silc_buffer_reset(&packet->buffer);
+
+    return packet;
+  }
+
+  SILC_LOG_DEBUG(("Get packet %p", packet));
+
+  /* Delete from freelist */
+  silc_list_del(engine->packet_pool, packet);
+
+  silc_mutex_unlock(engine->lock);
+
+  return packet;
+}
+
+
+/******************************** Packet API ********************************/
 
 /* Allocate new packet engine */
 
 SilcPacketEngine
-silc_packet_engine_start(SilcSchedule schedule, SilcRng rng, bool router,
+silc_packet_engine_start(SilcRng rng, SilcBool router,
                         SilcPacketCallbacks *callbacks,
                         void *callback_context)
 {
@@ -175,7 +323,7 @@ silc_packet_engine_start(SilcSchedule schedule, SilcRng rng, bool router,
 
   SILC_LOG_DEBUG(("Starting new packet engine"));
 
-  if (!schedule || !callbacks)
+  if (!callbacks)
     return NULL;
   if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
     return NULL;
@@ -188,7 +336,7 @@ silc_packet_engine_start(SilcSchedule schedule, SilcRng rng, bool router,
   engine->local_is_router = router;
   engine->callbacks = callbacks;
   engine->callback_context = callback_context;
-  engine->streams = silc_dlist_init();
+  silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
   silc_mutex_alloc(&engine->lock);
 
   /* Allocate packet free list */
@@ -202,6 +350,7 @@ silc_packet_engine_start(SilcSchedule schedule, SilcRng rng, bool router,
     if (!tmp)
       return NULL;
     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
+    silc_buffer_reset(&packet->buffer);
 
     silc_list_add(engine->packet_pool, packet);
   }
@@ -228,6 +377,7 @@ void silc_packet_engine_stop(SilcPacketEngine engine)
 /* Create new packet stream */
 
 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
+                                          SilcSchedule schedule,
                                           SilcStream stream)
 {
   SilcPacketStream ps;
@@ -251,17 +401,24 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
   if (!tmp)
     return NULL;
   silc_buffer_set(&ps->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
+  silc_buffer_reset(&ps->inbuf);
   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
   if (!tmp)
     return NULL;
   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
+  silc_buffer_reset(&ps->outbuf);
+
+  /* Initialize packet procesors list */
+  ps->process = silc_dlist_init();
 
   /* Set IO notifier callback */
-  silc_stream_set_notifier(ps->stream, silc_packet_stream_io, ps);
+  silc_stream_set_notifier(ps->stream, schedule, silc_packet_stream_io, ps);
+
+  silc_mutex_alloc(&ps->lock);
 
   /* Add to engine */
   silc_mutex_lock(engine->lock);
-  silc_dlist_add(engine->streams, ps);
+  silc_list_add(engine->streams, ps);
   silc_mutex_unlock(engine->lock);
 
   return ps;
@@ -273,14 +430,17 @@ void silc_packet_stream_destroy(SilcPacketStream stream)
 {
   if (!stream)
     return;
-  if (stream->refcnt > 1)
+
+  if (stream->refcnt > 1) {
+    stream->destroyed = TRUE;
     return;
+  }
 
   SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
 
   /* Delete from engine */
   silc_mutex_lock(stream->engine->lock);
-  silc_dlist_del(stream->engine->streams, stream);
+  silc_list_del(stream->engine->streams, stream);
   silc_mutex_unlock(stream->engine->lock);
 
   /* Clear and free buffers */
@@ -289,50 +449,175 @@ void silc_packet_stream_destroy(SilcPacketStream stream)
   silc_free(silc_buffer_steal(&stream->inbuf, NULL));
   silc_free(silc_buffer_steal(&stream->outbuf, NULL));
 
+  silc_dlist_uninit(stream->process);
+
   /* XXX */
 
   silc_free(stream);
 }
 
+/* Marks as router stream */
 
-/* Set new packet callbacks for stream */
+void silc_packet_stream_set_router(SilcPacketStream stream)
+{
+  stream->is_router = TRUE;
+}
 
-void silc_packet_stream_callbacks(SilcPacketStream stream,
-                                 SilcPacketCallbacks *callbacks,
-                                 void *callback_context)
+/* Links `callbacks' to `stream' for specified packet types */
+
+SilcBool silc_packet_stream_link(SilcPacketStream stream,
+                                SilcPacketCallbacks *callbacks,
+                                void *callback_context,
+                                int priority, ...)
 {
-  stream->callbacks = callbacks;
-  stream->callback_context = callback_context;
+  va_list ap;
+  SilcPacketProcess p, e;
+  SilcInt32 packet_type;
+  int i;
+
+  SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
+
+  if (!callbacks)
+    return FALSE;
+  if (!callbacks->packet_receive)
+    return FALSE;
+
+  p = silc_calloc(1, sizeof(*p));
+  if (!p)
+    return FALSE;
+
+  p->priority = priority;
+  p->callbacks = callbacks;
+  p->callback_context = callback_context;
+
+  silc_mutex_lock(stream->lock);
+
+  if (!stream->process) {
+    stream->process = silc_dlist_init();
+    if (!stream->process)
+      return FALSE;
+  }
+
+  /* According to priority set the procesor to correct position.  First
+     entry has the highest priority */
+  silc_dlist_start(stream->process);
+  while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
+    if (p->priority > e->priority) {
+      silc_dlist_insert(stream->process, p);
+      break;
+    }
+  }
+  if (!e)
+    silc_dlist_add(stream->process, p);
+
+  silc_mutex_unlock(stream->lock);
+
+  /* Get packet types to process */
+  va_start(ap, priority);
+  i = 1;
+  while (1) {
+    packet_type = va_arg(ap, SilcInt32);
+
+    if (packet_type == SILC_PACKET_ANY)
+      break;
+
+    if (packet_type == -1)
+      break;
+
+    p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
+    if (!p->types)
+      return FALSE;
+
+    p->types[i - 1] = (SilcPacketType)packet_type;
+    i++;
+  }
+  if (p->types)
+    p->types[i - 1] = 0;
+  va_end(ap);
+
+  silc_packet_stream_ref(stream);
+
+  return TRUE;
+}
+
+/* Unlinks `callbacks' from `stream'. */
+
+void silc_packet_stream_unlink(SilcPacketStream stream,
+                              SilcPacketCallbacks *callbacks,
+                              void *callback_context)
+{
+  SilcPacketProcess p;
+
+  SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
+                 callbacks, stream));
+
+  silc_mutex_lock(stream->lock);
+
+  silc_dlist_start(stream->process);
+  while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
+    if (p->callbacks == callbacks &&
+       p->callback_context == callback_context) {
+      silc_dlist_del(stream->process, p);
+      silc_free(p);
+      break;
+    }
+
+  if (!silc_dlist_count(stream->process)) {
+    silc_dlist_uninit(stream->process);
+    stream->process = NULL;
+  }
+
+  silc_mutex_unlock(stream->lock);
+
+  silc_packet_stream_unref(stream);
 }
 
 /* Reference packet stream */
 
 void silc_packet_stream_ref(SilcPacketStream stream)
 {
+  silc_mutex_lock(stream->lock);
   stream->refcnt++;
+  silc_mutex_unlock(stream->lock);
 }
 
 /* Unreference packet stream */
 
 void silc_packet_stream_unref(SilcPacketStream stream)
 {
+  silc_mutex_lock(stream->lock);
   stream->refcnt--;
+  silc_mutex_unlock(stream->lock);
   if (stream->refcnt == 0)
     silc_packet_stream_destroy(stream);
 }
 
+/* Return engine */
+
+SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
+{
+  return stream->engine;
+}
+
 /* Set application context for packet stream */
 
-void silc_packet_set_context(SilcPacketStream stream, void *app_context)
+void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
 {
-  stream->app_context = app_context;
+  stream->stream_context = stream_context;
 }
 
 /* Return application context from packet stream */
 
 void *silc_packet_get_context(SilcPacketStream stream)
 {
-  return stream->app_context;
+  return stream->stream_context;
+}
+
+/* Return underlaying stream */
+
+SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
+{
+  return stream->stream;
 }
 
 /* Set ciphers for packet stream */
@@ -347,8 +632,8 @@ void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
 
 /* Return current ciphers from packet stream */
 
-bool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
-                            SilcCipher *receive)
+SilcBool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
+                                SilcCipher *receive)
 {
   if (!stream->send_key && !stream->receive_key)
     return FALSE;
@@ -373,8 +658,8 @@ void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
 
 /* Return current HMACs from packet stream */
 
-bool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
-                          SilcHmac *receive)
+SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
+                              SilcHmac *receive)
 {
   if (!stream->send_hmac && !stream->receive_hmac)
     return FALSE;
@@ -389,11 +674,12 @@ bool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
 
 /* Set SILC IDs to packet stream */
 
-bool silc_packet_set_ids(SilcPacketStream stream,
-                       SilcIdType src_id_type, const void *src_id,
-                        SilcIdType dst_id_type, const void *dst_id)
+SilcBool silc_packet_set_ids(SilcPacketStream stream,
+                            SilcIdType src_id_type, const void *src_id,
+                            SilcIdType dst_id_type, const void *dst_id)
 {
   SilcUInt32 len;
+  unsigned char tmp[32];
 
   if (!src_id && !dst_id)
     return FALSE;
@@ -402,7 +688,9 @@ bool silc_packet_set_ids(SilcPacketStream stream,
 
   if (src_id) {
     silc_free(stream->src_id);
-    stream->src_id = silc_id_id2str(src_id, src_id_type, &len);
+    if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len))
+      return FALSE;
+    stream->src_id = silc_memdup(tmp, len);
     if (!stream->src_id)
       return FALSE;
     stream->src_id_type = src_id_type;
@@ -411,7 +699,9 @@ bool silc_packet_set_ids(SilcPacketStream stream,
 
   if (dst_id) {
     silc_free(stream->dst_id);
-    stream->dst_id = silc_id_id2str(dst_id, dst_id_type, &len);
+    if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len))
+      return FALSE;
+    stream->dst_id = silc_memdup(tmp, len);
     if (!stream->dst_id)
       return FALSE;
     stream->dst_id_type = dst_id_type;
@@ -421,23 +711,64 @@ bool silc_packet_set_ids(SilcPacketStream stream,
   return TRUE;
 }
 
+/* Free packet */
+
+void silc_packet_free(SilcPacket packet)
+{
+  SilcPacketStream stream = packet->stream;
+
+  SILC_LOG_DEBUG(("Freeing packet %p", packet));
+
+#if defined(SILC_DEBUG)
+  /* Check for double free */
+  assert(packet->stream != NULL);
+#endif /* SILC_DEBUG */
+
+  silc_mutex_lock(stream->engine->lock);
+
+  packet->stream = NULL;
+  packet->src_id = packet->dst_id = NULL;
+  silc_buffer_reset(&packet->buffer);
+
+  /* Put the packet back to freelist */
+  silc_list_add(stream->engine->packet_pool, packet);
+
+  silc_mutex_unlock(stream->engine->lock);
+}
+
+/* Creates streamer */
+
+SilcStream silc_packet_streamer_create(SilcPacketStream stream,
+                                      SilcPacketType packet_type,
+                                      SilcPacketFlags packet_flags)
+{
+  /* XXX TODO */
+  return NULL;
+}
+
+/* Destroyes streamer */
+
+void silc_packet_streamer_destroy(SilcStream stream)
+{
+
+}
+
+
+/****************************** Packet Sending ******************************/
+
 /* Prepare outgoing data buffer for packet sending.  Returns the
    pointer to that buffer into the `packet'. */
 
-static bool silc_packet_send_prepare(SilcPacketStream stream,
-                                    SilcUInt32 totlen,
-                                                         SilcHmac hmac,
-                                    const SilcBuffer packet)
+static SilcBool silc_packet_send_prepare(SilcPacketStream stream,
+                                        SilcUInt32 totlen,
+                                        SilcHmac hmac,
+                                        SilcBuffer packet)
 {
   unsigned char *oldptr;
   unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
 
   totlen += mac_len;
 
-  /* If head is empty, the buffer is free for our use (no pending data) */
-  if (!silc_buffer_headlen(&stream->outbuf))
-    silc_buffer_reset(&stream->outbuf);
-
   /* Allocate more space if needed */
   if (silc_buffer_taillen(&stream->outbuf) < totlen) {
     if (!silc_buffer_realloc(&stream->outbuf,
@@ -448,33 +779,33 @@ static bool silc_packet_send_prepare(SilcPacketStream stream,
   /* Pull data area for the new packet, and return pointer to the start of
      the data area and save the pointer in to the `packet'.  MAC is pulled
      later after it's computed. */
-  oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen - mac_len);
+  oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
   silc_buffer_set(packet, oldptr, totlen);
+  silc_buffer_push_tail(packet, mac_len);
 
   return TRUE;
 }
 
-
 /* Internal routine to send packet */
 
-static bool silc_packet_send_raw(SilcPacketStream stream,
-                                SilcPacketType type,
-                                SilcPacketFlags flags,
-                                SilcIdType src_id_type,
-                                unsigned char *src_id,
-                                SilcUInt32 src_id_len,
-                                SilcIdType dst_id_type,
-                                unsigned char *dst_id,
-                                SilcUInt32 dst_id_len,
-                                const unsigned char *data,
-                                SilcUInt32 data_len,
-                                SilcCipher cipher,
-                                SilcHmac hmac)
+static SilcBool silc_packet_send_raw(SilcPacketStream stream,
+                                    SilcPacketType type,
+                                    SilcPacketFlags flags,
+                                    SilcIdType src_id_type,
+                                    unsigned char *src_id,
+                                    SilcUInt32 src_id_len,
+                                    SilcIdType dst_id_type,
+                                    unsigned char *dst_id,
+                                    SilcUInt32 dst_id_len,
+                                    const unsigned char *data,
+                                    SilcUInt32 data_len,
+                                    SilcCipher cipher,
+                                    SilcHmac hmac)
 {
   unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
   int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
   int i, enclen, truelen, padlen;
-  const SilcBufferStruct packet;
+  SilcBufferStruct packet;
 
   SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d,"
                  "data len %d", silc_get_packet_name(type), stream->send_psn,
@@ -510,22 +841,24 @@ static bool silc_packet_send_raw(SilcPacketStream stream,
       SILC_PACKET_PADLEN_MAX(truelen, block_len, padlen);
     else
       SILC_PACKET_PADLEN(truelen, block_len, padlen);
+
+    enclen += padlen;
   }
 
   /* Remove implementation specific flags */
   flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
 
+  /* Get random padding */
+  for (i = 0; i < padlen; i++) tmppad[i] =
+                                silc_rng_get_byte_fast(stream->engine->rng);
+
+  silc_mutex_lock(stream->lock);
+
   /* Get packet pointer from the outgoing buffer */
-  if (!silc_packet_send_prepare(stream, truelen + padlen, hmac, &packet))
+  if (!silc_packet_send_prepare(stream, truelen + padlen, hmac, &packet)) {
+    silc_mutex_unlock(stream->lock);
     return FALSE;
-
-  /* Get random padding */
-  if (stream->engine->rng)
-    for (i = 0; i < padlen; i++) tmppad[i] =
-                                          silc_rng_get_byte_fast(stream->engine->rng);
-  else
-    for (i = 0; i < padlen; i++) tmppad[i] =
-                                          silc_rng_global_get_byte_fast();
+  }
 
   /* Create the packet.  This creates the SILC header, adds padding, and
      the actual packet data. */
@@ -544,22 +877,26 @@ static bool silc_packet_send_raw(SilcPacketStream stream,
                         SILC_STR_UI_XNSTRING(tmppad, padlen),
                         SILC_STR_UI_XNSTRING(data, data_len),
                         SILC_STR_END);
-  if (i < 0)
+  if (i < 0) {
+    silc_mutex_unlock(stream->lock);
     return FALSE;
+  }
 
   SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
                   packet.data, silc_buffer_len(&packet));
 
   /* Encrypt the packet */
   if (cipher)
-    if (!silc_cipher_encrypt(cipher, packet.data, packet.data, enclen, NULL)) {
+    if (!silc_cipher_encrypt(cipher, packet.data, packet.data,
+                            enclen, NULL)) {
       SILC_LOG_ERROR(("Packet encryption failed"));
+      silc_mutex_unlock(stream->lock);
       return FALSE;
     }
 
   /* Compute HMAC */
   if (hmac) {
-    unsigned char mac[32], psn[4];
+    unsigned char psn[4];
     SilcUInt32 mac_len;
 
     /* MAC is computed from the entire encrypted packet data, and put
@@ -574,41 +911,45 @@ static bool silc_packet_send_raw(SilcPacketStream stream,
   }
 
   /* Write the packet to the stream */
-  while (silc_buffer_len(&packet) > 0) {
-    i = silc_stream_write(stream->stream, packet.data,
-                         silc_buffer_len(&packet));
+  while (silc_buffer_len(&stream->outbuf) > 0) {
+    i = silc_stream_write(stream->stream, stream->outbuf.data,
+                         silc_buffer_len(&stream->outbuf));
     if (i == 0) {
       /* EOS */
-      SILC_PACKET_CALLBACK_EOS(stream);
       silc_buffer_reset(&stream->outbuf);
+      silc_mutex_unlock(stream->lock);
+      SILC_PACKET_CALLBACK_EOS(stream);
       return FALSE;
     }
 
     if (i == -2) {
       /* Error */
-      SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_WRITE);
       silc_buffer_reset(&stream->outbuf);
+      silc_mutex_unlock(stream->lock);
+      SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_WRITE);
       return FALSE;
     }
 
     if (i == -1) {
       /* Cannot write now, write later. */
-      silc_buffer_pull(&packet, silc_buffer_len(&packet));
+      silc_mutex_unlock(stream->lock);
       return TRUE;
     }
 
     /* Wrote data */
-    silc_buffer_pull(&packet, i);
+    silc_buffer_pull(&stream->outbuf, i);
   }
+  silc_buffer_reset(&stream->outbuf);
 
+  silc_mutex_unlock(stream->lock);
   return TRUE;
 }
 
 /* Sends a packet */
 
-bool silc_packet_send(SilcPacketStream stream,
-                     SilcPacketType type, SilcPacketFlags flags,
-                     const unsigned char *data, SilcUInt32 data_len)
+SilcBool silc_packet_send(SilcPacketStream stream,
+                         SilcPacketType type, SilcPacketFlags flags,
+                         const unsigned char *data, SilcUInt32 data_len)
 {
   return silc_packet_send_raw(stream, type, flags,
                              stream->src_id_type,
@@ -624,141 +965,47 @@ bool silc_packet_send(SilcPacketStream stream,
 
 /* Sends a packet, extended routine */
 
-bool silc_packet_send_ext(SilcPacketStream stream,
-                         SilcPacketType type, SilcPacketFlags flags,
-                         SilcIdType src_id_type, void *src_id,
-                         SilcIdType dst_id_type, void *dst_id,
-                         const unsigned char *data, SilcUInt32 data_len,
-                         SilcCipher cipher, SilcHmac hmac)
+SilcBool silc_packet_send_ext(SilcPacketStream stream,
+                             SilcPacketType type, SilcPacketFlags flags,
+                             SilcIdType src_id_type, void *src_id,
+                             SilcIdType dst_id_type, void *dst_id,
+                             const unsigned char *data, SilcUInt32 data_len,
+                             SilcCipher cipher, SilcHmac hmac)
 {
-  bool ret;
-  unsigned char *src_id_data = NULL, *dst_id_data = NULL;
+  unsigned char src_id_data[32], dst_id_data[32];
   SilcUInt32 src_id_len, dst_id_len;
 
-  /* XXX non-allocating id2str needed! */
-
   if (src_id)
-    src_id_data = silc_id_id2str(src_id, src_id_type, &src_id_len);
-  if (src_id)
-    dst_id_data = silc_id_id2str(dst_id, dst_id_type, &dst_id_len);
-
-  ret = silc_packet_send_raw(stream, type, flags,
-                            src_id_type,
-                            src_id_data,
-                            src_id_len,
-                            dst_id_type,
-                            dst_id_data,
-                            dst_id_len,
-                            data, data_len,
-                            cipher,
-                            hmac);
-
-  silc_free(src_id_data);
-  silc_free(dst_id_data);
-
-  return ret;
-}
-
-/* Our stream IO notifier callback. */
-
-static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
-                                 void *context)
-{
-  SilcPacketStream ps = context;
-  int ret;
-
-  switch (status) {
-
-  case SILC_STREAM_CAN_WRITE:
-    if (!silc_buffer_headlen(&ps->outbuf))
-      return;
-
-    SILC_LOG_DEBUG(("Writing pending data to stream"));
-
-    /* Write pending data to stream */
-    silc_buffer_push(&ps->outbuf, silc_buffer_headlen(&ps->outbuf));
-    while (silc_buffer_len(&ps->outbuf) > 0) {
-      ret = silc_stream_write(ps->stream, ps->outbuf.data,
-                             silc_buffer_len(&ps->outbuf));
-      if (ret == 0) {
-       /* EOS */
-       SILC_PACKET_CALLBACK_EOS(ps);
-       silc_buffer_reset(&ps->outbuf);
-       return;
-      }
-
-      if (ret == -2) {
-       /* Error */
-       SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
-       silc_buffer_reset(&ps->outbuf);
-       return;
-      }
-
-      if (ret == -1) {
-       /* Cannot write now, write later. */
-       silc_buffer_pull(&ps->outbuf, silc_buffer_len(&ps->outbuf));
-       return;
-      }
-
-      /* Wrote data */
-      silc_buffer_pull(&ps->outbuf, ret);
-    }
-
-    break;
-
-  case SILC_STREAM_CAN_READ:
-    SILC_LOG_DEBUG(("Reading data from stream"));
-
-    /* Make sure we have fair amount of free space in inbuf */
-    if (silc_buffer_taillen(&ps->inbuf) < SILC_PACKET_DEFAULT_SIZE)
-      if (!silc_buffer_realloc(&ps->inbuf, silc_buffer_truelen(&ps->inbuf) +
-                              SILC_PACKET_DEFAULT_SIZE * 2))
-       return;
-
-    /* Read data from stream */
-    ret = silc_stream_read(ps->stream, &ps->inbuf.tail,
-                          silc_buffer_taillen(&ps->inbuf));
-
-    if (ret == 0) {
-      /* EOS */
-      SILC_PACKET_CALLBACK_EOS(ps);
-      silc_buffer_reset(&ps->inbuf);
-      return;
-    }
-
-    if (ret == -2) {
-      /* Error */
-      SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
-      silc_buffer_reset(&ps->inbuf);
-      return;
-    }
-
-    if (ret == -1) {
-      /* Cannot read now, do it later. */
-      silc_buffer_pull(&ps->inbuf, silc_buffer_len(&ps->inbuf));
-      return;
-    }
-
-    /* Read some data */
-    silc_buffer_pull_tail(&ps->inbuf, ret);
+    if (!silc_id_id2str(src_id, src_id_type, src_id_data,
+                       sizeof(src_id_data), &src_id_len))
+      return FALSE;
+  if (dst_id)
+    if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
+                       sizeof(dst_id_data), &dst_id_len))
+      return FALSE;
 
-    /* Now process the data */
-    silc_packet_read_process(ps);
+  return silc_packet_send_raw(stream, type, flags,
+                             src_id_type,
+                             src_id_data,
+                             src_id_len,
+                             dst_id_type,
+                             dst_id_data,
+                             dst_id_len,
+                             data, data_len,
+                             cipher,
+                             hmac);
+}
 
-    break;
 
-  default:
-    break;
-  }
-}
+/***************************** Packet Receiving *****************************/
 
 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
 
-static bool silc_packet_check_mac(SilcHmac hmac,
-                                 const unsigned char *data,
-                                 SilcUInt32 data_len,
-                                 const unsigned char *packet_mac,
-                                 SilcUInt32 sequence)
+static SilcBool silc_packet_check_mac(SilcHmac hmac,
+                                     const unsigned char *data,
+                                     SilcUInt32 data_len,
+                                     const unsigned char *packet_mac,
+                                     SilcUInt32 sequence)
 {
   /* Check MAC */
   if (hmac) {
@@ -791,7 +1038,7 @@ static bool silc_packet_check_mac(SilcHmac hmac,
 
 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
                               SilcUInt32 sequence, SilcBuffer buffer,
-                              bool normal)
+                              SilcBool normal)
 {
   if (normal == TRUE) {
     if (cipher) {
@@ -837,7 +1084,7 @@ static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
    parsed. The buffer sent must be already decrypted before calling this
    function. */
 
-static bool silc_packet_parse(SilcPacketStream stream, SilcPacket packet)
+static SilcBool silc_packet_parse(SilcPacket packet)
 {
   SilcBuffer buffer = &packet->buffer;
   SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
@@ -898,11 +1145,94 @@ static bool silc_packet_parse(SilcPacketStream stream, SilcPacket packet)
   silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
                   packet->src_id_len + packet->dst_id_len + padlen);
 
-  SILC_LOG_DEBUG(("Incoming packet type: %d", packet->type));
+  SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
+                 silc_get_packet_name(packet->type)));
 
   return TRUE;
 }
 
+/* Dispatch packet to application */
+
+static void silc_packet_dispatch(SilcPacket packet)
+{
+  SilcPacketStream stream = packet->stream;
+  SilcPacketProcess p;
+  SilcBool default_sent = FALSE;
+  SilcPacketType *pt;
+
+  /* Parse the packet */
+  if (!silc_packet_parse(packet)) {
+    SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
+    silc_packet_free(packet);
+    return;
+  }
+
+  /* Dispatch packet to all packet processors that want it */
+
+  if (!stream->process) {
+    /* Send to default processor as no others exist */
+    SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
+    if (!stream->engine->callbacks->
+       packet_receive(stream->engine, stream, packet,
+                      stream->engine->callback_context,
+                      stream->stream_context))
+      silc_packet_free(packet);
+    return;
+  }
+
+  silc_dlist_start(stream->process);
+  while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
+
+    /* If priority is 0 or less, we send to default processor first
+       because default processor has 0 priority */
+    if (!default_sent && p->priority <= 0) {
+      SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
+      default_sent = TRUE;
+      if (stream->engine->callbacks->
+         packet_receive(stream->engine, stream, packet,
+                        stream->engine->callback_context,
+                        stream->stream_context)) {
+       return;
+      }
+    }
+
+    /* Send to processor */
+    if (!p->types) {
+      /* Send all packet types */
+      SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
+      if (p->callbacks->packet_receive(stream->engine, stream, packet,
+                                      p->callback_context,
+                                      stream->stream_context))
+       return;
+    } else {
+      /* Send specific types */
+      for (pt = p->types; *pt; pt++)
+       if (*pt == packet->type) {
+         SILC_LOG_DEBUG(("Dispatching packet to %p callbacks",
+                         p->callbacks));
+         if (p->callbacks->packet_receive(stream->engine, stream, packet,
+                                          p->callback_context,
+                                          stream->stream_context))
+           return;
+         break;
+       }
+    }
+  }
+
+  if (!default_sent) {
+    /* Send to default processor as it has not been sent yet */
+    SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
+    if (stream->engine->callbacks->
+       packet_receive(stream->engine, stream, packet,
+                      stream->engine->callback_context,
+                      stream->stream_context))
+      return;
+  }
+
+  /* If we got here, no one wanted the packet, so drop it */
+  silc_packet_free(packet);
+}
+
 /* Process incoming data and parse packets. */
 
 static void silc_packet_read_process(SilcPacketStream stream)
@@ -912,7 +1242,7 @@ static void silc_packet_read_process(SilcPacketStream stream)
   SilcUInt32 paddedlen, mac_len, block_len;
   unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
-  bool normal = TRUE;
+  SilcBool normal = TRUE;
   int ret;
 
   /* Parse the packets from the data */
@@ -957,7 +1287,6 @@ static void silc_packet_read_process(SilcPacketStream stream)
                      "(%d bytes)",
                      paddedlen + mac_len - silc_buffer_len(&stream->inbuf)));
       memset(tmp, 0, sizeof(tmp));
-/*      silc_buffer_reset(&stream->inbuf); */
       return;
     }
 
@@ -981,14 +1310,15 @@ static void silc_packet_read_process(SilcPacketStream stream)
     }
 
     /* Allocate more space to packet buffer, if needed */
-    if (silc_buffer_len(&packet->buffer) < paddedlen) {
+    if (silc_buffer_truelen(&packet->buffer) < paddedlen) {
       if (!silc_buffer_realloc(&packet->buffer,
                               silc_buffer_truelen(&packet->buffer) +
                               (paddedlen -
                                silc_buffer_truelen(&packet->buffer)))) {
        SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
+       silc_packet_free(packet);
        memset(tmp, 0, sizeof(tmp));
-      silc_buffer_reset(&stream->inbuf);
+       silc_buffer_reset(&stream->inbuf);
        return;
       }
     }
@@ -1003,7 +1333,7 @@ static void silc_packet_read_process(SilcPacketStream stream)
        normal = FALSE;
       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
               (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
-               stream->engine->local_is_router == TRUE))
+               stream->is_router == TRUE))
        normal = TRUE;
     } else {
       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
@@ -1018,6 +1348,7 @@ static void silc_packet_read_process(SilcPacketStream stream)
                     stream->inbuf.data, paddedlen + mac_len);
 
     /* Put the decrypted part, and rest of the encrypted data, and decrypt */
+    silc_buffer_pull_tail(&packet->buffer, paddedlen);
     silc_buffer_put(&packet->buffer, header, block_len);
     silc_buffer_pull(&packet->buffer, block_len);
     silc_buffer_put(&packet->buffer, stream->inbuf.data + block_len,
@@ -1028,6 +1359,7 @@ static void silc_packet_read_process(SilcPacketStream stream)
                                stream->receive_psn, &packet->buffer, normal);
       if (ret < 0) {
        SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
+       silc_packet_free(packet);
        memset(tmp, 0, sizeof(tmp));
        return;
       }
@@ -1036,83 +1368,13 @@ static void silc_packet_read_process(SilcPacketStream stream)
     }
     silc_buffer_push(&packet->buffer, block_len);
 
-    /* Parse the packet */
-    if (!silc_packet_parse(stream, packet)) {
-      SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
-      memset(tmp, 0, sizeof(tmp));
-      return;
-    }
-
-    /* Send the packet to application */
-    SILC_PACKET_CALLBACK_PACKET(stream, packet);
-
     /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
     silc_buffer_pull(&stream->inbuf, paddedlen + mac_len);
-  }
-
-  SILC_LOG_DEBUG(("Resetting inbound buffer"));
-  silc_buffer_reset(&stream->inbuf);
-}
-
-/* Allocate packet */
 
-SilcPacket silc_packet_alloc(SilcPacketEngine engine)
-{
-  SilcPacket packet;
-
-  SILC_LOG_DEBUG(("Packet pool count %d",
-                 silc_list_count(engine->packet_pool)));
-
-  silc_mutex_lock(engine->lock);
-
-  /* Get packet from freelist or allocate new one. */
-  packet = silc_list_get(engine->packet_pool);
-  if (!packet) {
-    silc_mutex_unlock(engine->lock);
-    packet = silc_calloc(1, sizeof(*packet));
-    if (!packet)
-      return NULL;
-    SILC_LOG_DEBUG(("Allocating new packet %p", packet));
-    return packet;
+    /* Dispatch the packet to application */
+    packet->stream = stream;
+    silc_packet_dispatch(packet);
   }
 
-  SILC_LOG_DEBUG(("Get packet %p", packet));
-
-  /* Delete from freelist */
-  silc_list_del(engine->packet_pool, packet);
-
-  silc_mutex_unlock(engine->lock);
-
-  return packet;
-}
-
-/* Free packet */
-
-void silc_packet_free(SilcPacketEngine engine, SilcPacket packet)
-{
-  SILC_LOG_DEBUG(("Freeing packet %p", packet));
-
-  silc_buffer_reset(&packet->buffer);
-
-  /* Put the packet back to freelist */
-  silc_mutex_lock(engine->lock);
-  silc_list_add(engine->packet_pool, packet);
-  silc_mutex_unlock(engine->lock);
-}
-
-/* Creates streamer */
-
-SilcStream silc_packet_streamer_create(SilcPacketStream stream,
-                                      SilcPacketType packet_type,
-                                      SilcPacketFlags packet_flags)
-{
-  /* XXX TODO */
-  return NULL;
-}
-
-/* Destroyes streamer */
-
-void silc_packet_streamer_destroy(SilcStream stream)
-{
-
+  silc_buffer_reset(&stream->inbuf);
 }
index fce2ebf5e5d7883596ec2237c4510114b85e39e7..eb3c97d762817882210ed453d9ca8565ccc06ef8 100644 (file)
  *
  * DESCRIPTION
  *
- * Implementation of the packet routines for sending and receiving
- * SILC Packets. These includes the data sending routines and data
- * reading routines, encrypting and decrypting routines, packet assembling
- * and packet parsing routines.
+ * The SILC secure binary packet protocol interface, provides interface for
+ * sending and receiving SILC packets.  The interface provides a packet engine,
+ * that can be used to receive packets from packet streams, and routines
+ * for sending all kinds of SILC packets.
+ *
+ * The packet engine and packet stream are thread safe.  They can be safely
+ * used in multi threaded environment.
  *
  ***/
 
@@ -54,7 +57,6 @@
 typedef SilcUInt8 SilcPacketType;
 
 /* SILC Packet types. */
-#define SILC_PACKET_NONE                0       /* NULL, never sent */
 #define SILC_PACKET_DISCONNECT          1       /* Disconnection */
 #define SILC_PACKET_SUCCESS             2       /* Success */
 #define SILC_PACKET_FAILURE             3       /* Failure */
@@ -86,6 +88,9 @@ typedef SilcUInt8 SilcPacketType;
 
 #define SILC_PACKET_PRIVATE              200     /* Private range start  */
 #define SILC_PACKET_MAX                  255     /* RESERVED */
+
+#define SILC_PACKET_NONE                0       /* RESERVED */
+#define SILC_PACKET_ANY                  0
 /***/
 
 /****d* silccore/SilcPacketAPI/SilcPacketFlags
@@ -153,21 +158,25 @@ typedef struct SilcPacketStreamStruct *SilcPacketStream;
  *    callback.  The application can parse the data payload from the
  *    SilcPacket.  Also packet type, flags, and sender and destination
  *    IDs are available.  The application must free the packet with the
- *    silc_packet_free function.
+ *    silc_packet_free function if it takes it in for processing.
+ *
+ *    The list pointer `next' can be used by the application to put the
+ *    packet context in a list during processing, if needed.
  *
  * SOURCE
  */
 typedef struct SilcPacketStruct {
-  struct SilcPacketStruct *next;
-  SilcBufferStruct buffer;              /* Packet data payload */
-  unsigned char *src_id;                /* Source ID */
-  unsigned char *dst_id;                /* Destination ID */
-  unsigned int src_id_len  : 6;                 /* Source ID length */
-  unsigned int src_id_type : 2;                 /* Source ID type */
-  unsigned int dst_id_len  : 6;                 /* Destination ID length */
-  unsigned int dst_id_type : 2;                 /* Destination ID type */
-  SilcPacketType type;                  /* Packet type */
-  SilcPacketFlags flags;                /* Packet flags */
+  struct SilcPacketStruct *next;     /* List pointer, application may set */
+  SilcPacketStream stream;          /* Packet stream this packet is from */
+  SilcBufferStruct buffer;          /* Packet data payload */
+  unsigned char *src_id;            /* Source ID */
+  unsigned char *dst_id;            /* Destination ID */
+  unsigned int src_id_len  : 6;             /* Source ID length */
+  unsigned int src_id_type : 2;             /* Source ID type */
+  unsigned int dst_id_len  : 6;             /* Destination ID length */
+  unsigned int dst_id_type : 2;             /* Destination ID type */
+  SilcPacketType type;              /* Packet type */
+  SilcPacketFlags flags;            /* Packet flags */
 } *SilcPacket;
 /***/
 
@@ -181,7 +190,8 @@ typedef struct SilcPacketStruct {
  *
  *    Packet errors.  This is returned in the error callback.  If application
  *    needs the actual lower level stream error, it needs to retrieve it
- *    from the actual stream.
+ *    from the actual stream.  It can retrieve the underlaying stream from
+ *    the packet stream by calling silc_packet_stream_get_stream function.
  *
  * SOURCE
  */
@@ -199,25 +209,54 @@ typedef enum {
  *
  * SYNOPSIS
  *
- *    typedef void (*SilcPacketReceiveCb)(SilcPacketEngine engine,
- *                                        SilcPacketStream stream,
- *                                        SilcPacket packet,
- *                                        void *callback_context,
- *                                        void *app_context);
+ *    typedef SilcBool (*SilcPacketReceiveCb)(SilcPacketEngine engine,
+ *                                            SilcPacketStream stream,
+ *                                            SilcPacket packet,
+ *                                            void *callback_context,
+ *                                            void *stream_context);
  *
  * DESCRIPTION
  *
  *    The packet receive callback is called by the packet engine when a new
  *    SILC Packet has arrived.  The application must free the returned
- *    SilcPacket with silc_packet_free.  This callback is set in the
- *    SilcPacketCallbacks structure.
+ *    SilcPacket with silc_packet_free if it takes the packet in for
+ *    processing.  This callback is set in the SilcPacketCallbacks structure.
+ *    The `callback_context' is the context set as argument in the
+ *    silc_packet_engine_start function.  The `stream_context' is stream
+ *    specific context that was set by calling silc_packet_set_context.
+ *
+ *    If the application takes the received packet `packet' into processing
+ *    TRUE must be returned.  If FALSE is returned the packet engine will
+ *    pass the packet to other packet processor, if one has been linked
+ *    to the stream with silc_packet_stream_link function.  If no extra
+ *    processor is linked the packet is dropped.
+ *
+ * EXAMPLE
+ *
+ *    SilcBool
+ *    silc_foo_packet_receive_cb(SilcPacketEngine engine,
+ *                               SilcPacketStream stream, SilcPacket packet,
+ *                               void *callback_context, void *stream_context)
+ *    {
+ *      Application ctx = callback_context;
+ *
+ *      // If we're not up yet, let's not process the packet
+ *      if (ctx->initialized == FALSE)
+ *        return FALSE;
+ *
+ *      // Process the incoming packet...
+ *      ...
+ *
+ *      // It's our packet now, no one else will get it
+ *      return TRUE;
+ *    }
  *
  ***/
-typedef void (*SilcPacketReceiveCb)(SilcPacketEngine engine,
-                                   SilcPacketStream stream,
-                                   SilcPacket packet,
-                                   void *callback_context,
-                                   void *app_context);
+typedef SilcBool (*SilcPacketReceiveCb)(SilcPacketEngine engine,
+                                       SilcPacketStream stream,
+                                       SilcPacket packet,
+                                       void *callback_context,
+                                       void *stream_context);
 
 /****f* silccore/SilcPacketAPI/SilcPacketEosCb
  *
@@ -226,7 +265,7 @@ typedef void (*SilcPacketReceiveCb)(SilcPacketEngine engine,
  *    typedef void (*SilcPacketEosCb)(SilcPacketEngine engine,
  *                                    SilcPacketStream stream,
  *                                    void *callback_context,
- *                                    void *app_context);
+ *                                    void *stream_context);
  *
  * DESCRIPTION
  *
@@ -240,7 +279,7 @@ typedef void (*SilcPacketReceiveCb)(SilcPacketEngine engine,
 typedef void (*SilcPacketEosCb)(SilcPacketEngine engine,
                                SilcPacketStream stream,
                                void *callback_context,
-                               void *app_context);
+                               void *stream_context);
 
 /****f* silccore/SilcPacketAPI/SilcPacketErrorCb
  *
@@ -250,7 +289,7 @@ typedef void (*SilcPacketEosCb)(SilcPacketEngine engine,
  *                                      SilcPacketStream stream,
  *                                      SilcPacketError error,
  *                                      void *callback_context,
- *                                      void *app_context);
+ *                                      void *stream_context);
  *
  * DESCRIPTION
  *
@@ -263,7 +302,7 @@ typedef void (*SilcPacketErrorCb)(SilcPacketEngine engine,
                                  SilcPacketStream stream,
                                  SilcPacketError error,
                                  void *callback_context,
-                                 void *app_context);
+                                 void *stream_context);
 
 /****s* silccore/SilcPacketAPI/SilcPacketStream
  *
@@ -294,30 +333,27 @@ typedef struct {
  * SYNOPSIS
  *
  *    SilcPacketEngine
- *    silc_packet_engine_start(SilcSchedule schedule, SilcRng rng, bool router,
+ *    silc_packet_engine_start(SilcRng rng, SilcBool router,
  *                             SilcPacketCallbacks *callbacks,
  *                             void *callback_context);
  *
  * DESCRIPTION
  *
  *    Create new packet engine for processing incoming and outgoing packets.
- *    If `rng' is non-NULL that RNG will be used to create necessary random
- *    numbers during packet processing.  If NULL, Global RNG will be used.
  *    If `router' is  TRUE then the application is considered to be router
  *    server, and certain packets are handled differently.  Client and normal
  *    server must set it to FALSE.  The `callbacks' is a SilcPacketCallbacks
  *    structure provided by the caller which includes the callbacks that is
- *    called when for example packet is received, or end of stream is called
+ *    called when for example packet is received, or end of stream is called.
  *
  * NOTES
  *
- *    The packet engine is thread safe.  Also the `schedule' and `rng' are
- *    thread safe.  You can use one packet engine in multi threaded
- *    application.
+ *    The packet engine is thread safe.  You can use one packet engine in
+ *    multi threaded application.
  *
  ***/
 SilcPacketEngine
-silc_packet_engine_start(SilcSchedule schedule, SilcRng rng, bool router,
+silc_packet_engine_start(SilcRng rng, SilcBool router,
                         SilcPacketCallbacks *callbacks,
                         void *callback_context);
 
@@ -340,6 +376,7 @@ void silc_packet_engine_stop(SilcPacketEngine engine);
  * SYNOPSIS
  *
  *    SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
+ *                                               SilcSchedule schedule,
  *                                               SilcStream stream);
  *
  * DESCRIPTION
@@ -361,12 +398,12 @@ void silc_packet_engine_stop(SilcPacketEngine engine);
  *    to create SILC Packet Streamer with silc_packet_streamer_create, which
  *    can be used with silc_stream_read and silc_stream_write.
  *
- *    The SilcPacketStream is not thread safe.  If you share same stream
- *    with multiple threads concurrency control need to be employed.  It
- *    is recommended to create new SilcPacketStream for every thread.
+ *    The SilcPacketStream is thread safe.  Same context can be safely used
+ *    in multi threaded environment.
  *
  ***/
 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
+                                          SilcSchedule schedule,
                                           SilcStream stream);
 
 /****f* silccore/SilcPacketAPI/silc_packet_stream_destroy
@@ -383,6 +420,22 @@ SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
  ***/
 void silc_packet_stream_destroy(SilcPacketStream stream);
 
+/****f* silccore/SilcPacketAPI/silc_packet_stream_set_router
+ *
+ * SYNOPSIS
+ *
+ *    void silc_packet_stream_set_router(SilcPacketStream stream);
+ *
+ * DESCRIPTION
+ *
+ *    When called sets the stream indicates by `stream' as SILC router
+ *    connection stream.  This causes that certain packets are handled
+ *    differently.  This must be called for router connection streams and
+ *    must not be called for any other stream.
+ *
+ ***/
+void silc_packet_stream_set_router(SilcPacketStream stream);
+
 /****f* silccore/SilcPacketAPI/silc_packet_streamer_create
  *
  * SYNOPSIS
@@ -447,36 +500,76 @@ void silc_packet_streamer_destroy(SilcStream stream);
  *    Returns the actual stream that is associated with the packet stream
  *    `stream'.  The caller must not free the returned stream.  The returned
  *    stream is the same pointer that was set for silc_packet_stream_create.
- *    This function couled be used for example when an error callback is
+ *    This function could be used for example when an error callback is
  *    called by the packet engine to retrieve the actual lower level error
  *    from the stream.
  *
  ***/
 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream);
 
-/****f* silccore/SilcPacketAPI/silc_packet_stream_callbacks
+/****f* silccore/SilcPacketAPI/silc_packet_stream_link
  *
  * SYNOPSIS
  *
- *    void silc_packet_stream_callbacks(SilcPacketStream stream,
- *                                      SilcPacketCallbacks *callbacks,
- *                                      void *callback_context);
+ *    SilcBool silc_packet_stream_link(SilcPacketStream stream,
+ *                                     SilcPacketCallbacks *callbacks,
+ *                                     void *callback_context,
+ *                                     int priority, ...);
  *
  * DESCRIPTION
  *
- *    This is optional function which can be used to set specific callbacks
- *    for the packet stream indicated by `stream'.  If these are set then
- *    `callbacks' will be used instead of the ones set for the function
- *    silc_packet_engine_start.  To reset the normal behaviour call this
- *    function again with `callbacks' as NULL.  Note that the responsibility
- *    of handling end of stream, and error conditions moves to the layer
- *    calling this function since the original callbacks set in the
- *    silc_packet_engine_start will not be called.
+ *    Links the packet processing callbacks indicated by `callbacks' into
+ *    the packet stream indicated by `stream' with priority `priority' for
+ *    the packet types given in the variable argument list.  This function
+ *    can be used to link to the packet stream for specific packet types
+ *    and receive them in the specified callbacks.  This way, a third party,
+ *    for example some library may attach itself into the packet stream
+ *    and receive and process certain packets.  The variable argument
+ *    list is ended with -1.  To link to receive all packets use
+ *    SILC_PACKET_ANY.
+ *
+ *    The default packet processing callbacks given as argument to the
+ *    silc_packet_engine_start has the priority 0.  Any priority higher
+ *    than 0 will then take precedence over the default callbacks.  Any
+ *    priority lower than 0 (negative value) will be processed after the
+ *    default callbacks.
+ *
+ *    Note that setting only the 'packet_receive' callback in the `callbacks'
+ *    is required.
+ *
+ * EXAMPLE
+ *
+ *    // Link to this packet stream, with high priority, for
+ *    // SILC_PACKET_CONNECTION_AUTH and SILC_PACKET_CONNECTION_AUTH_REQUEST
+ *    // packets. We don't care about other packets.
+ *    silc_packet_stream_link(stream, our_callbacks, our_context,
+ *                            1000000, SILC_PACKET_CONNECTION_AUTH,
+ *                            SILC_PACKET_CONNECTION_AUTH_REQUEST, -1);
  *
  ***/
-void silc_packet_stream_callbacks(SilcPacketStream stream,
-                                 SilcPacketCallbacks *callbacks,
-                                 void *callback_context);
+SilcBool silc_packet_stream_link(SilcPacketStream stream,
+                                SilcPacketCallbacks *callbacks,
+                                void *callback_context,
+                                int priority, ...);
+
+/****f* silccore/SilcPacketAPI/silc_packet_stream_unlink
+ *
+ * SYNOPSIS
+ *
+ *    void silc_packet_stream_unlink(SilcPacketStream stream,
+ *                                   SilcPacketCallbacks *callbacks,
+ *                                   void *callback_context);
+ *
+ * DESCRIPTION
+ *
+ *    Unlinks the `callbacks' with `callback_context' from the packet stream
+ *    indicated by `stream'.  This function must be called for the callbacks
+ *    that was linked to `stream' when they are not needed anymore.
+ *
+ ***/
+void silc_packet_stream_unlink(SilcPacketStream stream,
+                              SilcPacketCallbacks *callbacks,
+                              void *callback_context);
 
 /****f* silccore/SilcPacketAPI/silc_packet_stream_ref
  *
@@ -507,23 +600,37 @@ void silc_packet_stream_ref(SilcPacketStream stream);
  ***/
 void silc_packet_stream_unref(SilcPacketStream stream);
 
+/****f* silccore/SilcPacketAPI/silc_packet_get_engine
+ *
+ * SYNOPSIS
+ *
+ *    SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the packet engine from the `stream'.
+ *
+ ***/
+SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream);
+
 /****f* silccore/SilcPacketAPI/silc_packet_set_context
  *
  * SYNOPSIS
  *
- *    void silc_packet_set_context(SilcPacketStream stream, void *app_context);
+ *    void silc_packet_set_context(SilcPacketStream stream,
+ *                                 void *stream_context);
  *
  * DESCRIPTION
  *
- *    Set an application specific context to the stream.  The context will
+ *    Sets a stream specific context to the stream.  The context will
  *    be delivered to all callback functions, and it can be retrieved by
  *    calling silc_packet_get_context function as well.  Note that this is
  *    separate packet stream specific context, and not the same as
  *    `callback_context' in silc_packet_engine_start.  Both will be delivered
- *    to the callbacks.
+ *    to the callbacks, and this context as the `stream_context' argument.
  *
  ***/
-void silc_packet_set_context(SilcPacketStream stream, void *app_context);
+void silc_packet_set_context(SilcPacketStream stream, void *stream_context);
 
 /****f* silccore/SilcPacketAPI/silc_packet_get_context
  *
@@ -560,8 +667,9 @@ void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
  *
  * SYNOPSIS
  *
- *    bool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
- *                                 SilcCipher *receive);
+ *    SilcBool silc_packet_get_ciphers(SilcPacketStream stream,
+ *                                     SilcCipher *send,
+ *                                     SilcCipher *receive);
  *
  * DESCRIPTION
  *
@@ -569,8 +677,8 @@ void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
  *    FALSE if ciphers are not set.
  *
  ***/
-bool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
-                            SilcCipher *receive);
+SilcBool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
+                                SilcCipher *receive);
 
 /****f* silccore/SilcPacketAPI/silc_packet_set_hmacs
  *
@@ -594,8 +702,8 @@ void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
  *
  * SYNOPSIS
  *
- *    bool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
- *                               SilcHmac *receive);
+ *    SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
+ *                                   SilcHmac *receive);
  *
  * DESCRIPTION
  *
@@ -603,16 +711,16 @@ void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
  *    FALSE if HMACs are not set.
  *
  ***/
-bool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
-                          SilcHmac *receive);
+SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
+                              SilcHmac *receive);
 
 /****f* silccore/SilcPacketAPI/silc_packet_set_ids
  *
  * SYNOPSIS
  *
- *    bool silc_packet_set_ids(SilcPacketStream stream,
- *                             SilcIdType src_id_type, const void *src_id
- *                             SilcIdType dst_id_type, const void *dst_id);
+ *    SilcBool silc_packet_set_ids(SilcPacketStream stream,
+ *                                 SilcIdType src_id_type, const void *src_id
+ *                                 SilcIdType dst_id_type, const void *dst_id);
  *
  * DESCRIPTION
  *
@@ -624,39 +732,41 @@ bool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
  *    It is also possible to set only source or destination ID.
  *
  ***/
-bool silc_packet_set_ids(SilcPacketStream stream,
-                        SilcIdType src_id_type, const void *src_id,
-                        SilcIdType dst_id_type, const void *dst_id);
+SilcBool silc_packet_set_ids(SilcPacketStream stream,
+                            SilcIdType src_id_type, const void *src_id,
+                            SilcIdType dst_id_type, const void *dst_id);
 
 /****f* silccore/SilcPacketAPI/silc_packet_send
  *
  * SYNOPSIS
  *
- *    bool silc_packet_send(SilcPacketStream stream,
- *                          SilcPacketType type, SilcPacketFlags flags,
- *                          const unsigned char *data, SilcUInt32 data_len);
+ *    SilcBool silc_packet_send(SilcPacketStream stream,
+ *                              SilcPacketType type, SilcPacketFlags flags,
+ *                              const unsigned char *data,
+ *                              SilcUInt32 data_len);
  *
  * DESCRIPTION
  *
  *    Send `data' of length of `data_len' to the packet stream indicated by
  *    `stream'.  If ciphers and HMACs were set using silc_packet_set_ciphers
  *    and silc_packet_set_hmacs the packet will be encrypted and MAC will be
- *    generated for it.  If silc_packet_set_ids was used to set source and
+ *    computed for it.  If silc_packet_set_ids was used to set source and
  *    destination ID for the packet stream those IDs are used in the
  *    packet.  If IDs have not been set and they need to be provided then
  *    silc_packet_send_ext function should be used.  Otherwise, the packet
- *    will not have IDs set at all.
+ *    will not have IDs set at all.  Returns FALSE if packet could not be
+ *    sent.
  *
  ***/
-bool silc_packet_send(SilcPacketStream stream,
-                     SilcPacketType type, SilcPacketFlags flags,
-                     const unsigned char *data, SilcUInt32 data_len);
+SilcBool silc_packet_send(SilcPacketStream stream,
+                         SilcPacketType type, SilcPacketFlags flags,
+                         const unsigned char *data, SilcUInt32 data_len);
 
 /****f* silccore/SilcPacketAPI/silc_packet_send_ext
  *
  * SYNOPSIS
  *
- *    bool
+ *    SilcBool
  *    silc_packet_send_ext(SilcPacketStream stream,
  *                         SilcPacketType type, SilcPacketFlags flags,
  *                         SilcIdType src_id_type, void *srd_id,
@@ -666,38 +776,32 @@ bool silc_packet_send(SilcPacketStream stream,
  *
  * DESCRIPTION
  *
- *    This function can be used to specificly set different parameters of
- *    the SILC packet to be sent to the stream indicated by `stream'.  This
- *    function can be used to set specific IDs, cipher and HMAC to be used
- *    in packet creation. If `truelen' is provided that value is put to the
- *    SILC packet's truelen field, if it is zero the routine will calculate
- *    the truelen field for the packet.  If `padlen' is provided that value
- *    will be the length of the padding for the packet, if zero the routine
- *    will calculate necessary amount of padding for the packet.  This
- *    function can be used when specific ciphers, HMACs and IDs has not been
- *    set for the stream, or setting them for the stream is not suitable.
+ *    Same as silc_packet_send but with this function different sending
+ *    parameters can be sent as argument.  This function can be used to
+ *    set specific IDs, cipher and HMAC to be used in packet sending,
+ *    instead of the ones saved in the `stream'.
  *
  ***/
-bool silc_packet_send_ext(SilcPacketStream stream,
-                         SilcPacketType type, SilcPacketFlags flags,
-                         SilcIdType src_id_type, void *src_id,
-                         SilcIdType dst_id_type, void *dst_id,
-                         const unsigned char *data, SilcUInt32 data_len,
-                         SilcCipher cipher, SilcHmac hmac);
+SilcBool silc_packet_send_ext(SilcPacketStream stream,
+                             SilcPacketType type, SilcPacketFlags flags,
+                             SilcIdType src_id_type, void *src_id,
+                             SilcIdType dst_id_type, void *dst_id,
+                             const unsigned char *data, SilcUInt32 data_len,
+                             SilcCipher cipher, SilcHmac hmac);
 
 /****f* silccore/SilcPacketAPI/silc_packet_free
  *
  * SYNOPSIS
  *
- *    void silc_packet_free(SilcPacketEngine engine, SilcPacket packet);
+ *    void silc_packet_free(SilcPacket packet);
  *
  * DESCRIPTION
  *
  *    This function is used to free the SilcPacket pointer that application
  *    receives in the SilcPacketReceive callback.  Application must free
- *    the packet.
+ *    the packet if it takes it in to processing.
  *
  ***/
-void silc_packet_free(SilcPacketEngine engine, SilcPacket packet);
+void silc_packet_free(SilcPacket packet);
 
 #endif /* SILCPACKET_H */
index 8829a8509ff75b9bd96fe4347bc8858801ffa45d..6da212c929d85d0ca5ec60e6674e818a294db54f 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2003 Pekka Riikonen
+  Copyright (C) 2003 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcstatus.h"
 
 /* Returns arguments by the status type. */
@@ -56,8 +56,38 @@ SilcUInt32 silc_status_get_args(SilcStatus status,
 
   case SILC_STATUS_ERR_NO_SUCH_CLIENT_ID:
   case SILC_STATUS_ERR_BAD_CLIENT_ID:
+    {
+      SilcClientID client_id;
+      tmp = silc_argument_get_arg_type(args, 2, &len);
+      if (!tmp)
+       return 0;
+      if (silc_id_payload_parse_id(tmp, len, NULL, &client_id,
+                                  sizeof(client_id)))
+       return 0;
+      *ret_arg1 = silc_id_dup(&client_id, SILC_ID_CLIENT);
+      if (!(*ret_arg1))
+       return 0;
+      num = 1;
+    }
+    break;
+
   case SILC_STATUS_ERR_NO_SUCH_SERVER_ID:
   case SILC_STATUS_ERR_BAD_SERVER_ID:
+    {
+      SilcServerID server_id;
+      tmp = silc_argument_get_arg_type(args, 2, &len);
+      if (!tmp)
+       return 0;
+      if (silc_id_payload_parse_id(tmp, len, NULL, &server_id,
+                                  sizeof(server_id)))
+       return 0;
+      *ret_arg1 = silc_id_dup(&server_id, SILC_ID_SERVER);
+      if (!(*ret_arg1))
+       return 0;
+      num = 1;
+    }
+    break;
+
   case SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID:
   case SILC_STATUS_ERR_BAD_CHANNEL_ID:
   case SILC_STATUS_ERR_NOT_ON_CHANNEL:
@@ -66,31 +96,48 @@ SilcUInt32 silc_status_get_args(SilcStatus status,
   case SILC_STATUS_ERR_BANNED_FROM_CHANNEL:
   case SILC_STATUS_ERR_NO_CHANNEL_PRIV:
   case SILC_STATUS_ERR_NO_CHANNEL_FOPRIV:
-    tmp = silc_argument_get_arg_type(args, 2, &len);
-    if (!tmp)
-      return 0;
-    *ret_arg1 = silc_id_payload_parse_id(tmp, len, NULL);
-    if (!(*ret_arg1))
-      return 0;
-    num = 1;
+    {
+      SilcChannelID channel_id;
+      tmp = silc_argument_get_arg_type(args, 2, &len);
+      if (!tmp)
+       return 0;
+      if (silc_id_payload_parse_id(tmp, len, NULL, &channel_id,
+                                  sizeof(channel_id)))
+       return 0;
+      *ret_arg1 = silc_id_dup(&channel_id, SILC_ID_CHANNEL);
+      if (!(*ret_arg1))
+       return 0;
+      num = 1;
+    }
     break;
 
   case SILC_STATUS_ERR_USER_NOT_ON_CHANNEL:
   case SILC_STATUS_ERR_USER_ON_CHANNEL:
-    tmp = silc_argument_get_arg_type(args, 2, &len);
-    if (!tmp)
-      return 0;
-    *ret_arg1 = silc_id_payload_parse_id(tmp, len, NULL);
-    if (!(*ret_arg1))
-      return 0;
-    num = 1;
-    tmp = silc_argument_get_arg_type(args, 3, &len);
-    if (!tmp)
-      return num;
-    *ret_arg2 = silc_id_payload_parse_id(tmp, len, NULL);
-    if (!(*ret_arg2))
-      return num;
-    num = 2;
+    {
+      SilcClientID client_id;
+      SilcChannelID channel_id;
+      SilcIdType type;
+      tmp = silc_argument_get_arg_type(args, 2, &len);
+      if (!tmp)
+       return 0;
+      if (silc_id_payload_parse_id(tmp, len, &type, &client_id,
+                                  sizeof(client_id)))
+       return 0;
+      *ret_arg1 = silc_id_dup(&client_id, type);
+      if (!(*ret_arg1))
+       return 0;
+      num = 1;
+      tmp = silc_argument_get_arg_type(args, 3, &len);
+      if (!tmp)
+       return num;
+      if (silc_id_payload_parse_id(tmp, len, &type, &channel_id,
+                                  sizeof(channel_id)))
+       return 0;
+      *ret_arg2 = silc_id_dup(&channel_id, type);
+      if (!(*ret_arg2))
+       return num;
+      num = 2;
+    }
     break;
 
   default:
index 0b36d326a669e3f05c86f41d97ad0199457937aa..80675d1eab98ac84517ffeab090d41331bbf9e53 100644 (file)
@@ -29,7 +29,7 @@
    silc_argument_get_arg_type
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcargument.h"
 
 #define ARG_NUM 250
@@ -43,7 +43,7 @@ int main(int argc, char **argv)
   unsigned char **argvv, *a;
   SilcUInt32 *argvv_lens, l;
   SilcUInt32 *argvv_types, t;
-  bool success = FALSE;
+  SilcBool success = FALSE;
 
   if (argc > 1 && !strcmp(argv[1], "-d")) {
     silc_debug = 1;
index 39df5f219aa4b79e7fd107ece2770045541c08ba..b8308fd60b304eb1b7b54329819fa9ca55ac38d4 100644 (file)
@@ -39,7 +39,7 @@ Mean:          500 cycles =    51.2 mbits/sec
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "rijndael_internal.h"
 #include "aes.h"
 
index 3d9c12e4a10ce2d2c6a0fa80d0b654007d18d725..355d64a87f5b2911d72e7c8455188bd750411711 100644 (file)
@@ -33,7 +33,7 @@
  *
  */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "blowfish_internal.h"
 #include "blowfish.h"
 
index 934e37df1be69ba3ddfaf77430f3969788c0bbb7..d7f42ecfdded43140734518ae7624785c8850a50 100644 (file)
@@ -58,7 +58,7 @@ Mean:          674 cycles =    38.0 mbits/sec
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "cast_internal.h"
 #include "cast.h"
 
index b896df5b0530ce72301558335a1645b16e2eef5f..58d71a26c15c35cc3902999e85abcf70c0cfd5af 100644 (file)
@@ -18,7 +18,7 @@
  * will fill a supplied 16-byte array with the digest.
  */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "md5_internal.h"
 #include "md5.h"
 
index 65a362028e965b5f8e8661a85254fd76a360aeef..5a1a570986765ac81c4407206b3bea1a17c24c76 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "none.h"
 
 /* 
index 645c88dd8182c70e6f991923fe5c92e32e33e994..dfbe7e4376e23292c2205c43e6fb90740969fb32 100644 (file)
@@ -38,7 +38,7 @@
  *
  */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "rc5_internal.h"
 #include "rc5.h"
 
index e557901fa7dee3b3bba066d4badc3c2f36553d09..18399a5a393a0c49707d0803dad3eb402b27dab8 100644 (file)
@@ -75,7 +75,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "rsa_internal.h"
 #include "rsa.h"
 
index c75be8662245c5e822e952fc411475a17d8acafd..6943734cb88407ea2e773b5823d95b0eab14e4a0 100644 (file)
@@ -5,7 +5,7 @@ By Steve Reid <steve@edmweb.com>
 100% Public Domain
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "sha1_internal.h"
 #include "sha1.h"
 
index 45e07f29d80e96120e1c1b07134d5bab6f5edbbe..389787ab2cb923dc1c93b102e9fc6b4687325a63 100644 (file)
@@ -10,7 +10,7 @@
  *
  * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.org
  */
-#include "silcincludes.h"
+#include "silc.h"
 #include "sha256_internal.h"
 #include "sha256.h"
 
index 29ea8d792aab9ec74956ffbec1bf74d9df0268e9..2264d5cfc51b8212392aaccaf03f2ebf4c9c2821 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "ciphers.h"           /* Includes cipher definitions */
 
 /* The SilcCipher context */
index 04e7f2a1a17c800c40dae512fc569a8c734b8794..472b0ab8edeea4ffe11b6a53b1d32acf938b3387 100644 (file)
@@ -4,12 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.
-  
+
   This program 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
@@ -33,7 +33,7 @@
 /****s* silccrypt/SilcCipherAPI/SilcCipher
  *
  * NAME
- * 
+ *
  *    typedef struct { ... } SilcCipher;
  *
  * DESCRIPTION
@@ -56,7 +56,7 @@ typedef struct {
   SilcBool (*set_key_with_string)(void *, const unsigned char *, SilcUInt32);
   SilcBool (*encrypt)(void *, const unsigned char *, unsigned char *,
                  SilcUInt32, unsigned char *);
-  SilcBool (*decrypt)(void *, const unsigned char *, unsigned char *, 
+  SilcBool (*decrypt)(void *, const unsigned char *, unsigned char *,
                  SilcUInt32, unsigned char *);
   SilcUInt32 (*context_len)();
 } SilcCipherObject;
@@ -153,7 +153,7 @@ SilcBool silc_cipher_unregister(SilcCipherObject *cipher);
  *
  * DESCRIPTION
  *
- *    Function that registers all the default ciphers (all builtin ciphers). 
+ *    Function that registers all the default ciphers (all builtin ciphers).
  *    The application may use this to register the default ciphers if specific
  *    ciphers in any specific order is not wanted.
  *
@@ -182,7 +182,7 @@ SilcBool silc_cipher_unregister_all(void);
  *
  * DESCRIPTION
  *
- *    Allocates a new SILC cipher object. Function returns 1 on succes and 0 
+ *    Allocates a new SILC cipher object. Function returns 1 on succes and 0
  *    on error. The allocated cipher is returned in new_cipher argument. The
  *    caller must set the key to the cipher after this function has returned
  *    by calling the ciphers set_key function.
@@ -212,7 +212,7 @@ void silc_cipher_free(SilcCipher cipher);
  * DESCRIPTION
  *
  *    Returns TRUE if cipher `name' is supported.
- * 
+ *
  ***/
 SilcBool silc_cipher_is_supported(const unsigned char *name);
 
@@ -233,28 +233,30 @@ char *silc_cipher_get_supported(void);
  *
  * SYNOPSIS
  *
- *    SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
- *                             unsigned char *dst, SilcUInt32 len, 
- *                             unsigned char *iv);
+ *    SilcBool silc_cipher_encrypt(SilcCipher cipher,
+ *                                 const unsigned char *src,
+ *                                 unsigned char *dst, SilcUInt32 len,
+ *                                 unsigned char *iv);
  *
  * DESCRIPTION
  *
  *    Encrypts data from `src' into `dst' with the specified cipher and
  *    Initial Vector (IV).  If the `iv' is NULL then the cipher's internal
  *    IV is used.  The `src' and `dst' maybe same buffer.
- * 
+ *
  ***/
 SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
-                        unsigned char *dst, SilcUInt32 len, 
-                        unsigned char *iv);
+                            unsigned char *dst, SilcUInt32 len,
+                            unsigned char *iv);
 
 /****f* silccrypt/SilcCipherAPI/silc_cipher_decrypt
  *
  * SYNOPSIS
  *
- *    SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
- *                             unsigned char *dst, SilcUInt32 len, 
- *                             unsigned char *iv);
+ *    SilcBool silc_cipher_decrypt(SilcCipher cipher,
+ *                                 const unsigned char *src,
+ *                                 unsigned char *dst, SilcUInt32 len,
+ *                                 unsigned char *iv);
  *
  * DESCRIPTION
  *
@@ -264,8 +266,8 @@ SilcBool silc_cipher_encrypt(SilcCipher cipher, const unsigned char *src,
  *
  ***/
 SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
-                        unsigned char *dst, SilcUInt32 len, 
-                        unsigned char *iv);
+                            unsigned char *dst, SilcUInt32 len,
+                            unsigned char *iv);
 
 /****f* silccrypt/SilcCipherAPI/silc_cipher_set_key
  *
@@ -281,7 +283,7 @@ SilcBool silc_cipher_decrypt(SilcCipher cipher, const unsigned char *src,
  *
  ***/
 SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
-                        SilcUInt32 keylen);
+                            SilcUInt32 keylen);
 
 /****f* silccrypt/SilcCipherAPI/silc_cipher_set_iv
  *
@@ -291,7 +293,7 @@ SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key,
  *
  * DESCRIPTION
  *
- *    Sets the IV (initial vector) for the cipher.  The `iv' must be 
+ *    Sets the IV (initial vector) for the cipher.  The `iv' must be
  *    the size of the block size of the cipher.
  *
  ***/
@@ -305,9 +307,9 @@ void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv);
  *
  * DESCRIPTION
  *
- *    Returns the IV (initial vector) of the cipher.  The returned 
+ *    Returns the IV (initial vector) of the cipher.  The returned
  *    pointer must not be freed by the caller.
- * 
+ *
  ***/
 unsigned char *silc_cipher_get_iv(SilcCipher cipher);
 
@@ -320,7 +322,7 @@ unsigned char *silc_cipher_get_iv(SilcCipher cipher);
  * DESCRIPTION
  *
  *    Returns the key length of the cipher in bits.
- * 
+ *
  ***/
 SilcUInt32 silc_cipher_get_key_len(SilcCipher cipher);
 
index f486c26dad5fc0f4b1e937d89e98bd5fb107ade5..34aff02bb6adabed5f90f37855471eef3722963d 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silchash.c 
+  silchash.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #include "md5.h"
 #include "sha1.h"
@@ -36,7 +36,7 @@ SilcDList silc_hash_list = NULL;
 #endif /* SILC_EPOC */
 
 /* Default hash functions for silc_hash_register_default(). */
-const SilcHashObject silc_default_hash[] = 
+const SilcHashObject silc_default_hash[] =
 {
   { "sha256", 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
     silc_sha256_transform, silc_sha256_context_len },
@@ -119,7 +119,7 @@ SilcBool silc_hash_unregister(SilcHashObject *hash)
   return FALSE;
 }
 
-/* Function that registers all the default hash funcs (all builtin ones). 
+/* Function that registers all the default hash funcs (all builtin ones).
    The application may use this to register the default hash funcs if
    specific hash funcs in any specific order is not wanted. */
 
@@ -159,7 +159,7 @@ SilcBool silc_hash_unregister_all(void)
 SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
 {
   SilcHashObject *entry = NULL;
-  
+
   SILC_LOG_DEBUG(("Allocating new hash object"));
 
 #ifndef SILC_EPOC
@@ -263,8 +263,8 @@ char *silc_hash_get_supported(void)
     while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
       len += strlen(entry->name);
       list = silc_realloc(list, len + 1);
-      
-      memcpy(list + (len - strlen(entry->name)), 
+
+      memcpy(list + (len - strlen(entry->name)),
             entry->name, strlen(entry->name));
       memcpy(list + len, ",", 1);
       len++;
@@ -277,8 +277,8 @@ char *silc_hash_get_supported(void)
       entry = (SilcHashObject *)&(silc_default_hash[i]);
       len += strlen(entry->name);
       list = silc_realloc(list, len + 1);
-      
-      memcpy(list + (len - strlen(entry->name)), 
+
+      memcpy(list + (len - strlen(entry->name)),
             entry->name, strlen(entry->name));
       memcpy(list + len, ",", 1);
       len++;
@@ -293,7 +293,7 @@ char *silc_hash_get_supported(void)
 
 /* Creates the hash value and returns it to the return_hash argument. */
 
-void silc_hash_make(SilcHash hash, const unsigned char *data, 
+void silc_hash_make(SilcHash hash, const unsigned char *data,
                    SilcUInt32 len, unsigned char *return_hash)
 {
   silc_hash_init(hash);
@@ -378,15 +378,15 @@ char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
   babbleprint[0] = co[16];
 
   check = 1;
-  for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) { 
+  for (i = 0, k = 1; i < hash->hash->hash_len - 1; i += 2, k += 6) {
     a = (((hval[i] >> 6) & 3) + check) % 6;
     b = (hval[i] >> 2) & 15;
     c = ((hval[i] & 3) + (check / 6)) % 6;
     d = (hval[i + 1] >> 4) & 15;
     e = hval[i + 1] & 15;
-    
+
     check = ((check * 5) + (hval[i] * 7) + hval[i + 1]) % 36;
-    
+
     babbleprint[k + 0] = vo[a];
     babbleprint[k + 1] = co[b];
     babbleprint[k + 2] = vo[c];
@@ -402,7 +402,7 @@ char *silc_hash_babbleprint(SilcHash hash, const unsigned char *data,
     babbleprint[k + 0] = vo[a];
     babbleprint[k + 1] = co[b];
     babbleprint[k + 2] = vo[c];
-  } else { 
+  } else {
     a = check % 6;
     b = 16;
     c = check / 6;
index 56e3bc80bd212ece6d7910af3457fd6dfb7fb948..6b3abed3dc6376663c76592ccf48b813dccea4a0 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* HMAC context */
 struct SilcHmacStruct {
index cb716e7bb1b2fe98f72983eb7f241e978cce6013..240456ff481380d89647ee664654bb9700b4d430 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #include "rsa.h"
 
index 59806841d4dd2398ca089c41427cb32806393edb..eeaa240586c1a6878d280ba68fca094b2c778c68 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2003 Pekka Riikonen
+  Copyright (C) 1997 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -526,8 +526,9 @@ SilcUInt32 silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
  *    Encrypts. Returns FALSE on error.
  *
  ***/
-SilcBool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
-                      unsigned char *dst, SilcUInt32 *dst_len);
+SilcBool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src,
+                          SilcUInt32 src_len,
+                          unsigned char *dst, SilcUInt32 *dst_len);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_decrypt
  *
@@ -542,8 +543,9 @@ SilcBool silc_pkcs_encrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len
  *    Decrypts.  Returns FALSE on error.
  *
  ***/
-SilcBool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
-                      unsigned char *dst, SilcUInt32 *dst_len);
+SilcBool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src,
+                          SilcUInt32 src_len,
+                          unsigned char *dst, SilcUInt32 *dst_len);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign
  *
@@ -559,7 +561,7 @@ SilcBool silc_pkcs_decrypt(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len
  *
  ***/
 SilcBool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
-                   unsigned char *dst, SilcUInt32 *dst_len);
+                       unsigned char *dst, SilcUInt32 *dst_len);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify
  *
@@ -576,8 +578,8 @@ SilcBool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
  *
  ***/
 SilcBool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
-                     SilcUInt32 signature_len, unsigned char *data,
-                     SilcUInt32 data_len);
+                         SilcUInt32 signature_len, unsigned char *data,
+                         SilcUInt32 data_len);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_sign_with_hash
  *
@@ -594,8 +596,8 @@ SilcBool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
  *
  ***/
 SilcBool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
-                             unsigned char *src, SilcUInt32 src_len,
-                             unsigned char *dst, SilcUInt32 *dst_len);
+                                 unsigned char *src, SilcUInt32 src_len,
+                                 unsigned char *dst, SilcUInt32 *dst_len);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify_with_hash
  *
@@ -614,10 +616,10 @@ SilcBool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
  *
  ***/
 SilcBool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
-                               unsigned char *signature,
-                               SilcUInt32 signature_len,
-                               unsigned char *data,
-                               SilcUInt32 data_len);
+                                   unsigned char *signature,
+                                   SilcUInt32 signature_len,
+                                   unsigned char *data,
+                                   SilcUInt32 data_len);
 
 /****f* silccrypt/SilcPKCSAPI/silc_pkcs_encode_identifier
  *
index ed0bd9fc827bc346ec19690fb3017c9529c6ab03..bfdded05218f814f7ab93838cbe1d20bf3caae70 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcpkcs1.h"
 
 /* Minimum padding in block */
index 2e9d935e5c36f1161aa5221c3a0420be45b50b93..d32b708b1613dbee7a617df2d0ea86bc7b22b404 100644 (file)
@@ -25,7 +25,7 @@
  * This RNG has been rewritten twice since the creation.
  */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifndef WIN32
 #ifdef HAVE_GETSID
index a60f923e3f92360d1b28842927c56c20dea477e5..1048cc5173eaec438233e060723c2b9b5b587306 100644 (file)
@@ -1,5 +1,5 @@
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Test vectors from RFC3602. */
 
index 3a1759f2145139c2c1fca9874903ba446df7c264..8b41389b62eac75211d9db168d9a56de9fe6246e 100644 (file)
@@ -1,4 +1,4 @@
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Test vectors from RFC 2202 */
 
index 14e98b496f83142c2bde3ef52ddc79ffb11eb9b8..887453476e16912b719d5aabeda93a01e56eff5f 100644 (file)
@@ -1,4 +1,4 @@
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Test vectors from RFC 2202 */
 
index 1ff5db1d60adb1a3d1054cfc4c8859cc4ce88a6f..d9d687a0a2f92b9cc9bf96533428ff035795d316 100644 (file)
@@ -1,4 +1,4 @@
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Test vectors from draft-ietf-ipsec-ciph-sha-256-01.txt */
 
index 67822b97d49e93d3bb6b1c884535bbcb8ecc582c..2dac7d33771a81f33312727284c23c026313e9ed 100644 (file)
@@ -1,4 +1,4 @@
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Test vectors from RFC 1321 */
 
index c6569c8d1b698d3fad705a3429f3b32c6430a91f..7798c66dff6b840bbcde5de10506c0d4c945eac6 100644 (file)
@@ -1,4 +1,4 @@
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Test vectors from NIST secure hashing definition for SHA-1 */
 
index d84c73bf723a6af05db8408823357956611dcffc..ef0945b6dd40675464df1cd402ec577184f0b69e 100644 (file)
@@ -1,4 +1,4 @@
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Test vectors from NIST secure hashing definition for SHA-256 */
 
index 41ba8d4059dc7f8380b2b60222f9b2d401cc91bb..2e5f34e8d54d14bc0c9b24b463f8b274f292b00f 100644 (file)
@@ -1,5 +1,5 @@
 /* Tests API in silcpkcs.h */
-#include "silcincludes.h"
+#include "silc.h"
 
 int key_len = 2048;
 const unsigned char p[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
index cb5daec4b30d86fbb6a8dc447af5c2460528372b..5cd684820734f578ffcf6bad425140b6fe461bae 100644 (file)
@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include "silcincludes.h"
+#include "silc.h"
 
 #include "twofish.h"
 
index cf929540a14352922cf751895928f1a3464bb4ba..ebfc19a4749cf05137d61ab59112174cb3991db0 100644 (file)
@@ -39,7 +39,7 @@ Mean:          378 cycles =    67.8 mbits/sec
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "twofish_internal.h"
 #include "twofish.h"
 
index 5c6e0657ad5338284f89dab9f0f4ca2c35e4184e..dec30326546f4422779e855bf0d6d163bbecce86 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Table for finding multiplicative inverse */
 typedef struct {
index 876296493aed60a7305492e965a8ddd2f6673905..d3f29b64bacbcbce7d3664affe189715260b0392 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include <gmp.h>
 
 void silc_mp_init(SilcMPInt *mp)
index 1abbf5078fc5ec0f52a6711b4313c5a521958390..10b4f9e8f567065ca768048f0b8b54493feb81a9 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "mp_tfm.h"
 
 void silc_mp_init(SilcMPInt *mp)
index bcfa029ba7a4f9c39eefd964e5e5f3571ada5510..4ab83aebe490820058ae65849d9755b63d2c78c5 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "mp_tma.h"
 
 void silc_mp_init(SilcMPInt *mp)
index 9df0dbef46c2fb06c4a6f68f48d2e18f3beddb86..02b7e941024cd3f4be9d24101e9402c36accffc6 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Encodes MP integer into binary data. Returns allocated data that
    must be free'd by the caller. If `len' is provided the destination
index 4fb83231c3aab547fddf3a1b8e0c678b61ca4133..ed9b8848aaa908c7f071776c930e0541d6ddceea 100644 (file)
@@ -19,7 +19,7 @@
 /* Created: Mon Dec  8 16:35:37 GMT+0200 1997 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /*
    Fixed primetable for small prime division. We use this primetable to
diff --git a/lib/silcserver/DIRECTORY b/lib/silcserver/DIRECTORY
new file mode 100644 (file)
index 0000000..c92412f
--- /dev/null
@@ -0,0 +1,17 @@
+<!--
+@LIBRARY=SILC Server Library
+@FILENAME=silcserverlib.html
+@LINK=silcserver.html:SILC Server API Reference
+@LINK=silcserver_params.html:SILC Server Parameters API Reference
+-->
+
+<big><b>SILC Server Library</b></big>
+<br />
+<small>Directory: lib/server/</small>
+<br />
+<small>Library: libsilcserver.a, libsilcserver.lib</small>
+<br /><br />
+<b>Introduction</b>
+
+<br /><br />
+@LINKS@
diff --git a/lib/silcserver/Makefile.ad b/lib/silcserver/Makefile.ad
new file mode 100644 (file)
index 0000000..11d0e76
--- /dev/null
@@ -0,0 +1,43 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@silcnet.org>
+#
+#  Copyright (C) 2005 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; version 2 of the License.
+#
+#  This program 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 General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LTLIBRARIES = libsilcserver.la
+
+libsilcserver_la_SOURCES =             \
+       server.c                        \
+       server_entry.c                  \
+       server_send.c                   \
+       server_util.c                   \
+       server_params.c                 \
+       server_st_accept.c              \
+       server_st_command.c             \
+       server_st_command_reply.c       \
+       server_st_connect.c             \
+       server_st_packet.c              \
+       server_st_notify.c              \
+       server_st_query.c
+
+
+#ifdef SILC_DIST_TOOLKIT
+include_HEADERS=
+#endif SILC_DIST_TOOLKIT
+
+EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
+
+include $(top_srcdir)/Makefile.defines.in
diff --git a/lib/silcserver/server.c b/lib/silcserver/server.c
new file mode 100644 (file)
index 0000000..cf325a4
--- /dev/null
@@ -0,0 +1,898 @@
+/*
+
+  server.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+/*
+ * This is the actual SILC server than handles everything relating to
+ * servicing the SILC connections. This is also a SILC router as a router
+ * is also normal server.
+ */
+/* $Id$ */
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/************************** Types and definitions ***************************/
+
+
+/************************ Static utility functions **************************/
+
+/* Packet engine callback to receive a packet */
+
+static SilcBool silc_server_packet_receive(SilcPacketEngine engine,
+                                          SilcPacketStream stream,
+                                          SilcPacket packet,
+                                          void *callback_context,
+                                          void *stream_context)
+{
+  SilcServerThread thread = callback_context;
+  SilcEntryData data = silc_packet_get_context(stream);
+
+  /* Packets we do not handle */
+  switch (packet->type) {
+  case SILC_PACKET_HEARTBEAT:
+  case SILC_PACKET_SUCCESS:
+  case SILC_PACKET_FAILURE:
+  case SILC_PACKET_REJECT:
+  case SILC_PACKET_KEY_EXCHANGE:
+  case SILC_PACKET_KEY_EXCHANGE_1:
+  case SILC_PACKET_KEY_EXCHANGE_2:
+  case SILC_PACKET_REKEY:
+  case SILC_PACKET_REKEY_DONE:
+  case SILC_PACKET_CONNECTION_AUTH:
+  case SILC_PACKET_CONNECTION_AUTH_REQUEST:
+    return FALSE;
+    break;
+  }
+
+  /* Only specific packets can come without source ID present. */
+  if ((!packet->src_id || data->registered == FALSE) &&
+      packet->type != SILC_PACKET_NEW_CLIENT &&
+      packet->type != SILC_PACKET_NEW_SERVER &&
+      packet->type != SILC_PACKET_DISCONNECT)
+    return FALSE;
+
+  /* NEW_CLIENT and NEW_SERVER are accepted only without source ID
+     and for unregistered connection. */
+  if (packet->src_id && (packet->type == SILC_PACKET_NEW_CLIENT ||
+                        packet->type == SILC_PACKET_NEW_SERVER) &&
+      data->registered == TRUE)
+    return FALSE;
+
+  /* Add the packet to packet queue */
+  silc_list_add(thread->packet_queue, packet);
+
+  /* Signal thread that packet has arrived */
+  if (!thread->new_packet) {
+    thread->new_packet = TRUE;
+    SILC_FSM_SEMA_POST(&thread->wait_event);
+  }
+
+  return TRUE;
+}
+
+/* Packet engine callback to indicate end of stream */
+
+static void silc_server_packet_eos(SilcPacketEngine engine,
+                                  SilcPacketStream stream,
+                                  void *callback_context,
+                                  void *stream_context)
+{
+  SILC_LOG_DEBUG(("End of stream received"));
+}
+
+/* Packet engine callback to indicate error */
+
+static void silc_server_packet_error(SilcPacketEngine engine,
+                                    SilcPacketStream stream,
+                                    SilcPacketError error,
+                                    void *callback_context,
+                                    void *stream_context)
+{
+
+}
+
+/* Packet stream callbacks */
+static SilcPacketCallbacks silc_server_stream_cbs =
+{
+  silc_server_packet_receive,
+  silc_server_packet_eos,
+  silc_server_packet_error
+};
+
+/* Server FSM destructor */
+
+static void silc_server_destructor(SilcFSM fsm, void *fsm_context,
+                                  void *destructor_context)
+{
+
+}
+
+/* Creates new server thread.  Adds to server threads list automatically and
+   starts the thread.  Depending on server configuration the created thread
+   is either FSM thread of real thread. */
+
+static SilcServerThread silc_server_new_thread(SilcServer server)
+{
+  SilcServerThread thread;
+
+  SILC_LOG_DEBUG(("Creating new server thread"));
+
+  thread = silc_calloc(1, sizeof(*thread));
+  if (!thread)
+    return NULL;
+
+  thread->server = server;
+  silc_list_init(thread->new_conns, struct SilcServerAcceptStruct, next);
+
+  /* Start packet engine */
+  thread->packet_engine =
+    silc_packet_engine_start(server->rng, server->server_type == SILC_ROUTER,
+                            &silc_server_stream_cbs, thread);
+  if (!thread->packet_engine) {
+    silc_free(thread);
+    return NULL;
+  }
+
+  /* Add to server */
+  silc_list_add(server->threads, thread);
+
+  /* Start the thread */
+  silc_fsm_thread_init(&thread->thread, &server->fsm, thread,
+                      NULL, NULL, server->params->use_threads);
+  silc_fsm_start(&thread->thread, silc_server_thread_st_start);
+
+  /* Allocate data stack.  Its allocation is allowed to fail so we don't
+     check for it. */
+  thread->stack = silc_stack_alloc(0);
+
+  return thread;
+}
+
+/* Network listener callback to accept new connections */
+
+static void silc_server_accept_connection(SilcNetStatus status,
+                                         SilcStream stream, void *context)
+{
+  SilcServer server = context;
+  SilcServerAccept ac;
+
+  if (status != SILC_NET_OK) {
+    SILC_LOG_ERROR(("Error %d accepting new connection", status));
+    return;
+  }
+
+  ac = silc_calloc(1, sizeof(*ac));
+  if (!ac) {
+    silc_stream_destroy(stream);
+    return;
+  }
+  ac->stream = stream;
+
+  /* Add as new connection */
+  silc_list_add(server->new_conns, ac);
+
+  /* Signal server of new connection */
+  if (!server->new_connection) {
+    server->new_connection = TRUE;
+    SILC_FSM_SEMA_POST(&server->wait_event);
+  }
+}
+
+/* Packet thread destructor */
+
+static void silc_server_thread_packet_dest(SilcFSM fsm, void *fsm_context,
+                                          void *destructor_context)
+{
+  silc_fsm_free(fsm);
+}
+
+
+/****************************** Server thread *******************************/
+
+/* Thread's start function.  This may be FSM thread or real system thread,
+   depending on server configuration. */
+
+SILC_FSM_STATE(silc_server_thread_st_start)
+{
+  SilcServerThread thread = fsm_context;
+
+  SILC_LOG_DEBUG(("New server thread started"));
+
+  /*** Run thread's machine */
+  silc_fsm_init(&thread->fsm, thread, NULL, NULL, silc_fsm_get_schedule(fsm));
+  silc_fsm_sema_init(&thread->wait_event, &thread->fsm, 0);
+  silc_fsm_start_sync(&thread->fsm, silc_server_thread_st_run);
+
+  /* Signal server that we are up */
+  SILC_FSM_SEMA_POST(&thread->server->thread_up);
+
+  /* Wait here for this thread to finish */
+  return SILC_FSM_WAIT;
+}
+
+/* Thread's machine's main state where we wait for various events. */
+
+SILC_FSM_STATE(silc_server_thread_st_run)
+{
+  SilcServerThread thread = fsm_context;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Wait for events */
+  SILC_FSM_SEMA_WAIT(&thread->wait_event);
+
+  /* Process events */
+
+  if (thread->new_packet) {
+    /*** Packet received */
+    SilcPacket packet;
+    SilcFSMThread t;
+
+    SILC_LOG_DEBUG(("Processing incoming packets"));
+
+    /* Each packet is processed in FSM thread */
+    silc_list_start(thread->packet_queue);
+    while ((packet = silc_list_get(thread->packet_queue)) != SILC_LIST_END) {
+      t = silc_fsm_thread_alloc(fsm, thread, silc_server_thread_packet_dest,
+                               NULL, FALSE);
+      if (t) {
+       silc_fsm_set_state_context(t, packet);
+       silc_fsm_start_sync(t, silc_server_st_packet_received);
+      }
+    }
+
+    /* Empty the queue */
+    silc_list_init(thread->packet_queue, struct SilcPacketStruct, next);
+
+    thread->new_packet = FALSE;
+    return SILC_FSM_CONTINUE;
+  }
+
+  silc_mutex_lock(thread->server->lock);
+
+  if (thread->new_connection) {
+    /*** Accept new connection */
+    SilcServerAccept ac;
+
+    SILC_LOG_DEBUG(("Processing incoming connections"));
+
+    /* Accept the new connection in own thread */
+    silc_list_start(thread->new_conns);
+    while ((ac = silc_list_get(thread->new_conns)) != SILC_LIST_END) {
+      ac->thread = thread;
+      ac->t = silc_fsm_thread_alloc(&thread->fsm, ac,
+                                   silc_server_accept_connection_dest,
+                                   NULL, FALSE);
+      silc_fsm_start(ac->t, silc_server_st_accept_connection);
+    }
+
+    /* Empty the list */
+    silc_list_init(thread->new_conns, struct SilcServerAcceptStruct, next);
+
+    thread->new_connection = FALSE;
+    silc_mutex_unlock(thread->server->lock);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* NOT REACHED */
+#if defined(SILC_DEBUG)
+  assert(FALSE);
+#endif /* SILC_DEBUG */
+  return SILC_FSM_CONTINUE;
+}
+
+
+/*************************** Main server machine ****************************/
+
+/* The server's main state where we wait for various events */
+
+SILC_FSM_STATE(silc_server_st_run)
+{
+  SilcServer server = fsm_context;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Wait for events */
+  SILC_FSM_SEMA_WAIT(&server->wait_event);
+
+  /* Process events */
+
+  if (server->run_callback && server->running) {
+    /* Call running callbcak back to application */
+    server->run_callback = FALSE;
+    server->running(server, server->running_context);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (server->new_connection) {
+    /** New connection */
+    silc_fsm_next(fsm, silc_server_st_new_connection);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (server->connect_router) {
+    /** Connect to router(s) */
+    silc_fsm_next(fsm, silc_server_st_connect_router);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (server->get_statistics) {
+    /** Retrieve statistics */
+    silc_fsm_next(fsm, silc_server_st_get_stats);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (server->reconfigure) {
+    /** Reconfigure server */
+    silc_fsm_next(fsm, silc_server_st_reconfigure);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (server->server_shutdown) {
+    /** Shutdown server */
+    silc_fsm_next(fsm, silc_server_st_stop);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* NOT REACHED */
+#if defined(SILC_DEBUG)
+  assert(FALSE);
+#endif /* SILC_DEBUG */
+  return SILC_FSM_CONTINUE;
+}
+
+/* New connection received */
+
+SILC_FSM_STATE(silc_server_st_new_connection)
+{
+  SilcServer server = fsm_context;
+  SilcServerThread thread;
+  SilcServerAccept ac;
+
+  SILC_LOG_DEBUG(("Process new connections"));
+
+  silc_list_start(server->new_conns);
+  while ((ac = silc_list_get(server->new_conns)) != SILC_LIST_END) {
+
+    /* Find thread where to put this connection */
+    silc_list_start(server->threads);
+    while ((thread = silc_list_get(server->threads)) != SILC_LIST_END) {
+      if (!server->params->use_threads)
+       break;
+      if (thread->num_conns < server->params->connections_per_thread)
+       break;
+    }
+
+    if (!thread) {
+      /** Create new thread */
+      thread = silc_server_new_thread(server);
+      if (!thread) {
+       silc_list_del(server->new_conns, ac);
+       silc_stream_destroy(ac->stream);
+       silc_free(ac);
+       continue;
+      }
+
+      silc_fsm_next(fsm, silc_server_st_wait_new_thread);
+      return SILC_FSM_CONTINUE;
+    }
+
+    silc_list_del(server->new_conns, ac);
+
+    /* Give this connection to this thread */
+    silc_mutex_lock(server->lock);
+    silc_list_add(thread->new_conns, ac);
+    thread->num_conns++;
+
+    SILC_LOG_DEBUG(("Signal thread for new connection"));
+
+    /* Signal the thread for new connection */
+    if (!thread->new_connection) {
+      thread->new_connection = TRUE;
+      SILC_FSM_SEMA_POST(&thread->wait_event);
+    }
+    silc_mutex_unlock(server->lock);
+  }
+
+  server->new_connection = FALSE;
+
+  /** Connections processed */
+  silc_fsm_next(fsm, silc_server_st_run);
+  return SILC_FSM_CONTINUE;
+}
+
+/* Wait here until newly created thread is up */
+
+SILC_FSM_STATE(silc_server_st_wait_new_thread)
+{
+  SilcServer server = fsm_context;
+
+  /* Wait here until new thread is up */
+  SILC_FSM_SEMA_WAIT(&server->thread_up);
+
+  /** Process new connections */
+  silc_fsm_next(fsm, silc_server_st_new_connection);
+  return SILC_FSM_CONTINUE;
+}
+
+/* Stops server */
+
+SILC_FSM_STATE(silc_server_st_stop)
+{
+#if 0
+  SilcServer server = fsm_context;
+
+  SILC_LOG_INFO(("SILC Server shutting down"));
+
+  if (server->schedule) {
+    int i;
+
+    server->server_shutdown = TRUE;
+
+    /* Close all connections */
+    for (i = 0; i < server->config->param.connections_max; i++) {
+      if (!server->sockets[i])
+       continue;
+      if (!SILC_IS_LISTENER(server->sockets[i])) {
+       SilcSocketConnection sock = server->sockets[i];
+       SilcIDListData idata = sock->user_data;
+
+       if (idata)
+         idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+       silc_schedule_task_del_by_context(server->schedule,
+                                         server->sockets[i]);
+       silc_schedule_task_del_by_fd(server->schedule,
+                                    server->sockets[i]->sock);
+       silc_server_disconnect_remote(server, server->sockets[i],
+                                     SILC_STATUS_OK,
+                                     "Server is shutting down");
+       if (server->sockets[i]) {
+         if (sock->user_data)
+           silc_server_free_sock_user_data(server, sock,
+                                           "Server is shutting down");
+         silc_socket_free(sock);
+       }
+      } else {
+       silc_socket_free(server->sockets[i]);
+       server->sockets[i] = NULL;
+        server->stat.conn_num--;
+      }
+    }
+
+    /* We are not connected to network anymore */
+    server->standalone = TRUE;
+
+    silc_schedule_stop(server->schedule);
+    silc_schedule_uninit(server->schedule);
+    server->schedule = NULL;
+
+    silc_free(server->sockets);
+    server->sockets = NULL;
+  }
+
+  silc_server_protocols_unregister();
+#endif /* 0 */
+
+  /** Wait events */
+  silc_fsm_next(fsm, silc_server_st_run);
+  return SILC_FSM_CONTINUE;
+}
+
+/* Reconfigure server */
+
+SILC_FSM_STATE(silc_server_st_reconfigure)
+{
+  SilcServer server = fsm_context;
+
+  SILC_LOG_DEBUG(("Reconfiguring server"));
+
+  /** Wait events */
+  server->reconfigure = FALSE;
+  silc_fsm_next(fsm, silc_server_st_run);
+  return SILC_FSM_CONTINUE;
+}
+
+/* Get statistics */
+
+SILC_FSM_STATE(silc_server_st_get_stats)
+{
+  SilcServer server = fsm_context;
+
+  SILC_LOG_DEBUG(("Getting statistics"));
+
+  /** Wait events */
+  server->get_statistics = FALSE;
+  silc_fsm_next(fsm, silc_server_st_run);
+  return SILC_FSM_CONTINUE;
+}
+
+
+/**************************** Public interface ******************************/
+
+/* Allocates server context and returns it */
+
+SilcServer silc_server_alloc(void *app_context, SilcServerParams params,
+                            SilcSchedule schedule)
+{
+  SilcServer server;
+  SilcServerParamInterface iface;
+  SilcBool id_created = FALSE;
+
+  SILC_LOG_DEBUG(("Allocating new server"));
+
+  if (!schedule || !params)
+    return NULL;
+
+  server = silc_calloc(1, sizeof(*server));
+  if (!server)
+    return NULL;
+
+  server->app_context = app_context;
+  server->schedule = schedule;
+  server->params = params;
+  server->server_type = SILC_SERVER;
+  server->standalone = TRUE;
+#ifdef SILC_SIM
+  server->sim = silc_dlist_init();
+#endif
+
+#if defined(SILC_DEBUG)
+  /* Set debugging on if configured */
+  if (params->debug_string) {
+    silc_log_debug(TRUE);
+    silc_log_set_debug_string(params->debug_string);
+  }
+#endif /* SILC_DEBUG */
+
+  /* Allocate ID caches */
+  server->clients = silc_idcache_alloc(0, SILC_ID_CLIENT,
+                                      silc_server_destructor_client, server);
+  server->servers = silc_idcache_alloc(0, SILC_ID_SERVER,
+                                      silc_server_destructor_server, server);
+  server->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL,
+                                       silc_server_destructor_channel,
+                                       server);
+  if (!server->clients || !server->servers || !server->channels) {
+    SILC_LOG_ERROR(("Could not allocate ID cache"));
+    goto err;
+  }
+
+  /* Allocate key repository */
+  server->repository = silc_skr_alloc(schedule);
+  if (!server->repository) {
+    SILC_LOG_ERROR(("Could not allocate key repository"));
+    goto err;
+  }
+
+  /* Allocate server lock */
+  if (!silc_mutex_alloc(&server->lock)) {
+    SILC_LOG_DEBUG(("Could not allocate server lock"));
+    goto err;
+  }
+
+  /* Init FSM */
+  silc_fsm_init(&server->fsm, server, silc_server_destructor, NULL, schedule);
+
+  /* Init semaphore signallers */
+  silc_fsm_sema_init(&server->wait_event, &server->fsm, 0);
+  silc_fsm_sema_init(&server->thread_up, &server->fsm, 0);
+
+  /* Initialize lists */
+  silc_list_init(server->new_conns, struct SilcServerAcceptStruct, next);
+  silc_list_init(server->command_pool, struct SilcServerCommandStruct, next);
+
+#if 0
+  /* Register all paramsured ciphers, PKCS and hash functions. */
+  if (!silc_server_params_register_ciphers(server))
+    silc_cipher_register_default();
+  if (!silc_server_params_register_pkcs(server))
+    silc_pkcs_register_default();
+  if (!silc_server_params_register_hashfuncs(server))
+    silc_hash_register_default();
+  if (!silc_server_params_register_hmacs(server))
+    silc_hmac_register_default();
+#else
+    silc_cipher_register_default();
+    silc_pkcs_register_default();
+    silc_hash_register_default();
+    silc_hmac_register_default();
+#endif /* 0 */
+
+  /* Initialize random number generator for the server. */
+  server->rng = silc_rng_alloc();
+  if (!server->rng) {
+    SILC_LOG_ERROR(("Could not allocate RNG"));
+    goto err;
+  }
+  silc_rng_init(server->rng);
+  silc_rng_global_init(server->rng);
+
+  /* Initialize hash functions for server to use */
+  silc_hash_alloc("md5", &server->md5hash);
+  silc_hash_alloc("sha1", &server->sha1hash);
+
+  /* Steal public and private key from the params object */
+  server->public_key = server->params->server_info->public_key;
+  server->private_key = server->params->server_info->private_key;
+  server->params->server_info->public_key = NULL;
+  server->params->server_info->private_key = NULL;
+
+  /* Allocate PKCS context for local public and private keys */
+  if (!silc_pkcs_alloc(server->public_key->name, SILC_PKCS_SILC,
+                      &server->pkcs))
+    goto err;
+  silc_pkcs_public_key_set(server->pkcs, server->public_key);
+  silc_pkcs_private_key_set(server->pkcs, server->private_key);
+
+  /* Create network listener(s) */
+  server->listeners = silc_dlist_init();
+  if (!server->listeners)
+    goto err;
+  silc_list_start(params->server_info->interfaces);
+  while ((iface = silc_list_get(params->server_info->interfaces)) !=
+        SILC_LIST_END) {
+
+    if (!id_created) {
+      /* Create a Server ID for the server */
+      if (!silc_server_create_server_id(server, iface->ip, iface->port,
+                                       &server->id)) {
+       SILC_LOG_ERROR(("Could not create Server ID"));
+       goto err;
+      }
+
+      id_created = TRUE;
+    }
+
+    SilcNetServer listener =
+      silc_net_create_server((const char **)&iface->ip, 1, iface->port,
+                            params->require_reverse_lookup,
+                            server->schedule,
+                            silc_server_accept_connection, server);
+    if (!listener) {
+      SILC_LOG_ERROR(("Could not bind %s on %d", iface->ip, iface->port));
+      goto err;
+    }
+
+    silc_dlist_add(server->listeners, listener);
+  }
+
+  /* First, register log files paramsuration for error output */
+  //  silc_server_params_setlogfiles(server);
+
+  /* Init watcher lists */
+  server->watcher_list =
+    silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL,
+                         silc_hash_data_compare, (void *)CLIENTID_HASH_LEN,
+                         NULL, NULL, TRUE);
+  if (!server->watcher_list)
+    goto err;
+#if 0
+  server->watcher_list_pk =
+    silc_hash_table_alloc(1, silc_hash_public_key, NULL,
+                         silc_hash_public_key_compare, NULL,
+                         NULL, NULL, TRUE);
+  if (!server->watcher_list_pk)
+    goto err;
+#endif /* 0 */
+
+  server->server_name = server->params->server_info->server_name;
+  server->params->server_info->server_name = NULL;
+
+#if 0
+  /* If server connections has been paramsured then we must be router as
+     normal server cannot have server connections, only router connections. */
+  if (server->params->servers) {
+    SilcServerParamsServer *ptr = server->params->servers;
+
+    server->server_type = SILC_ROUTER;
+    while (ptr) {
+      if (ptr->backup_router) {
+       server->server_type = SILC_BACKUP_ROUTER;
+       server->backup_router = TRUE;
+       server->id_entry->server_type = SILC_BACKUP_ROUTER;
+       break;
+      }
+      ptr = ptr->next;
+    }
+  }
+#endif /* 0 */
+
+  if (server->server_type == SILC_ROUTER)
+    server->stat.routers++;
+
+  return server;
+
+ err:
+  return NULL;
+}
+
+/* Free's the SILC server context */
+
+void silc_server_free(SilcServer server)
+{
+#if 0
+  SilcIDCacheList list;
+  SilcIDCacheEntry cache;
+
+  if (!server)
+    return;
+
+#ifdef SILC_SIM
+  {
+    SilcSim sim;
+    silc_dlist_start(server->sim);
+    while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
+      silc_dlist_del(server->sim, sim);
+      silc_sim_close(sim);
+      silc_sim_free(sim);
+    }
+    silc_dlist_uninit(server->sim);
+  }
+#endif
+
+  silc_server_backup_free(server);
+  silc_server_params_unref(&server->params_ref);
+  if (server->rng)
+    silc_rng_free(server->rng);
+  if (server->pkcs)
+    silc_pkcs_free(server->pkcs);
+  if (server->public_key)
+    silc_pkcs_public_key_free(server->public_key);
+  if (server->private_key)
+    silc_pkcs_private_key_free(server->private_key);
+  if (server->pending_commands)
+    silc_dlist_uninit(server->pending_commands);
+  if (server->id_entry)
+    silc_idlist_del_server(server->local_list, server->id_entry);
+
+  /* Delete all channels */
+  list = NULL;
+  if (silc_idcache_get_all(server->local_list->channels, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_channel(server->local_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_channel(server->local_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+  list = NULL;
+  if (silc_idcache_get_all(server->global_list->channels, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_channel(server->global_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_channel(server->global_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+
+  if (server->pk_hash)
+    silc_hash_table_free(server->pk_hash);
+
+  /* Delete all clients */
+  list = NULL;
+  if (silc_idcache_get_all(server->local_list->clients, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_client(server->local_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_client(server->local_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+  list = NULL;
+  if (silc_idcache_get_all(server->global_list->clients, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_client(server->global_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_client(server->global_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+
+
+  /* Delete all servers */
+  list = NULL;
+  if (silc_idcache_get_all(server->local_list->servers, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_server(server->local_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_server(server->local_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+  list = NULL;
+  if (silc_idcache_get_all(server->global_list->servers, &list) &&
+      silc_idcache_list_first(list, &cache)) {
+    silc_idlist_del_server(server->global_list, cache->context);
+    while (silc_idcache_list_next(list, &cache))
+      silc_idlist_del_server(server->global_list, cache->context);
+  }
+  if (list)
+    silc_idcache_list_free(list);
+
+#endif /* 0 */
+
+  silc_idcache_free(server->clients);
+  silc_idcache_free(server->servers);
+  silc_idcache_free(server->channels);
+  silc_hash_table_free(server->watcher_list);
+  silc_hash_table_free(server->watcher_list_pk);
+
+  silc_hash_free(server->md5hash);
+  silc_hash_free(server->sha1hash);
+  silc_hmac_unregister_all();
+  silc_hash_unregister_all();
+  silc_cipher_unregister_all();
+  silc_pkcs_unregister_all();
+}
+
+/* Starts the SILC server FSM machine and returns immediately.  The
+   scheduler must be run or be running already when this returns. */
+
+void silc_server_run(SilcServer server, SilcServerRunning running,
+                    void *running_context)
+{
+  SILC_LOG_INFO(("Starting SILC server"));
+
+  server->starttime = time(NULL);
+  server->running = running;
+  server->running_context = running_context;
+
+  /* Start the server */
+  silc_fsm_start_sync(&server->fsm, silc_server_st_run);
+
+  /* Signal the application when we are running */
+  server->run_callback = TRUE;
+  SILC_FSM_SEMA_POST(&server->wait_event);
+
+  /* Signal to connect to router */
+  server->connect_router = TRUE;
+  SILC_FSM_SEMA_POST(&server->wait_event);
+
+  /* Start getting statistics from the network on normal server */
+  if (server->server_type != SILC_ROUTER) {
+    server->get_statistics = TRUE;
+    SILC_FSM_SEMA_POST(&server->wait_event);
+  }
+}
+
+/* Stops the SILC server */
+
+void silc_server_stop(SilcServer server, SilcServerStop stopped,
+                     void *stop_context)
+{
+  SILC_LOG_INFO(("Stopping SILC server"));
+
+  server->stopped = stopped;
+  server->stop_context = stop_context;
+
+  /* Signal that server is going down */
+  server->server_shutdown = TRUE;
+  SILC_FSM_SEMA_POST(&server->wait_event);
+}
+
+/* Disconnects remote connection */
+
+SilcBool silc_server_disconnect(SilcServer server,
+                               SilcPacketStream stream,
+                               SilcStatus error,
+                               const char *error_string)
+{
+  return TRUE;
+}
diff --git a/lib/silcserver/server_entry.c b/lib/silcserver/server_entry.c
new file mode 100644 (file)
index 0000000..6effe75
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+
+  server_entry.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program 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 General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/************************ Static utility functions **************************/
+
+/* Foreach callbcak to free all users from the channel when deleting a
+   channel entry. */
+
+static void silc_server_del_channel_foreach(void *key, void *context,
+                                           void *user_context)
+{
+  SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
+
+  SILC_LOG_DEBUG(("Removing client %s from channel %s",
+                 chl->client->nickname ? chl->client->nickname :
+                 (unsigned char *)"", chl->channel->channel_name));
+
+  /* Remove the context from the client's channel hash table as that
+     table and channel's user_list hash table share this same context. */
+  silc_hash_table_del(chl->client->channels, chl->channel);
+  silc_free(chl);
+}
+
+
+/****************************** Server entry ********************************/
+
+void silc_server_destructor_server(SilcIDCache cache,
+                                  const SilcIDCacheEntry entry,
+                                  void *destructor_context,
+                                  void *app_context)
+{
+
+}
+
+/* Adds new server entry to server */
+
+SilcServerEntry silc_server_add_server(SilcServer server,
+                                      const char *server_name,
+                                      SilcServerType server_type,
+                                      SilcServerID *id,
+                                      SilcPacketStream origin)
+{
+  SilcServerEntry entry;
+  char *server_namec = NULL;
+
+  if (!id || !origin)
+    return NULL;
+
+  entry = silc_calloc(1, sizeof(*entry));
+  if (!entry)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Adding server entry %p %s", entry,
+                 silc_id_render(id, SILC_ID_SERVER)));
+
+  /* Normalize name.  This is cached, original is in server context.  */
+  if (server_name) {
+    server_namec = silc_identifier_check(server_name, strlen(server_name),
+                                        SILC_STRING_UTF8, 256, NULL);
+    if (!server_namec) {
+      silc_free(entry);
+      return NULL;
+    }
+
+    entry->server_name = strdup(server_name);
+    if (!server->server_name) {
+      silc_free(server_namec);
+      silc_free(entry);
+      return NULL;
+    }
+  }
+
+  entry->server_type = server_type;
+  entry->id = *id;
+  entry->stream = origin;
+
+  /* Add to cache */
+  if (!silc_idcache_add(server->servers, server_namec, &entry->id,
+                       entry)) {
+    silc_free(server_namec);
+    silc_free(entry->server_name);
+    silc_free(entry);
+    return NULL;
+  }
+
+  /* Take reference of the packet stream */
+  silc_packet_stream_ref(origin);
+
+  return entry;
+}
+
+/* Delete server entry */
+
+SilcBool silc_server_del_server(SilcServer server, SilcServerEntry entry)
+{
+  SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
+                 entry->server_name : "??", &entry->id ?
+                 silc_id_render(&entry->id, SILC_ID_SERVER) : "??"));
+
+  /* Delete */
+  if (!silc_idcache_del_by_context(server->servers, entry, NULL)) {
+    SILC_LOG_ERROR(("Unknown server %s, could not delete from cache",
+                   &entry->id ? silc_id_render(&entry->id, SILC_ID_SERVER) :
+                   "??"));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Find server by Server ID */
+
+SilcServerEntry
+silc_server_find_server_by_id(SilcServer server,
+                             SilcServerID *id,
+                             SilcBool registered,
+                             SilcIDCacheEntry *ret_entry)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcServerEntry entry;
+
+  if (!id)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Find Server ID (%s)",
+                 silc_id_render(id, SILC_ID_SERVER)));
+
+  if (!silc_idcache_find_by_id_one(server->servers, (void *)id,
+                                  &id_cache))
+    return NULL;
+
+  entry = id_cache->context;
+
+  if (entry && registered && !(entry->data.registered))
+    return NULL;
+
+  if (ret_entry)
+    *ret_entry = id_cache;
+
+  SILC_LOG_DEBUG(("Found"));
+
+  return entry;
+}
+
+/* Find server by name.  The 'name' must be normalized already. */
+
+SilcServerEntry
+silc_server_find_server_by_name(SilcServer server, char *name,
+                               SilcBool registered,
+                               SilcIDCacheEntry *ret_entry)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcServerEntry entry;
+
+  SILC_LOG_DEBUG(("Find server by name `%s'", name));
+
+  if (!silc_idcache_find_by_name_one(server->servers, name, &id_cache))
+    return NULL;
+
+  entry = id_cache->context;
+
+  if (entry && registered && !(entry->data.registered))
+    return NULL;
+
+  if (ret_entry)
+    *ret_entry = id_cache;
+
+  SILC_LOG_DEBUG(("Found"));
+
+  return entry;
+}
+
+/* Find server by connection parameters, hostname and port */
+
+SilcServerEntry
+silc_server_find_server_by_conn(SilcServer server, char *hostname,
+                               int port, SilcBool registered,
+                               SilcIDCacheEntry *ret_entry)
+{
+  SilcIDCacheEntry id_cache;
+  SilcServerEntry entry;
+  SilcStream stream;
+  SilcList list;
+  const char *h;
+  SilcUInt16 p;
+
+  SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
+
+  if (!silc_idcache_get_all(server->servers, &list))
+    return NULL;
+
+  while ((id_cache = silc_list_get(list)) != SILC_LIST_END) {
+    entry = id_cache->context;
+    stream = silc_packet_stream_get_stream(entry->stream);
+
+    if (entry && registered && !(entry->data.registered))
+      continue;
+
+    if (silc_socket_stream_get_info(stream, NULL, &h, NULL, &p)) {
+      if (silc_utf8_strcasecmp(hostname, h) && p == port)
+       break;
+    }
+  }
+  if (!id_cache)
+    entry = NULL;
+
+  if (ret_entry)
+    *ret_entry = id_cache;
+
+  SILC_LOG_DEBUG(("Found"));
+
+  return entry;
+}
+
+/* Replaces old Server ID with new one */
+
+SilcServerEntry
+silc_server_replace_server_id(SilcServer server, SilcServerID *old_id,
+                             SilcServerID *new_id)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcServerEntry entry;
+
+  if (!old_id || !new_id)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Replacing Server ID %s",
+                 silc_id_render(old_id, SILC_ID_SERVER)));
+  SILC_LOG_DEBUG(("New Server ID %s",
+                 silc_id_render(new_id, SILC_ID_SERVER)));
+
+  if (!silc_idcache_find_by_id_one(server->servers, (void *)old_id,
+                                  &id_cache))
+    return NULL;
+
+  entry = id_cache->context;
+  entry->id = *new_id;
+
+  if (!silc_idcache_update(server->servers, id_cache, old_id, &entry->id,
+                          NULL, NULL)) {
+    SILC_LOG_ERROR(("Error updating Server ID"));
+    return NULL;
+  }
+
+  SILC_LOG_DEBUG(("Replaced"));
+
+  return entry;
+}
+
+
+/****************************** Client entry ********************************/
+
+void silc_server_destructor_client(SilcIDCache cache,
+                                  const SilcIDCacheEntry entry,
+                                  void *destructor_context,
+                                  void *app_context)
+{
+
+}
+
+/* Adds new client to server */
+
+SilcClientEntry silc_server_add_client(SilcServer server,
+                                      const char *nickname,
+                                      const char *username,
+                                      const char *userinfo,
+                                      SilcClientID *id,
+                                      SilcUInt32 mode,
+                                      SilcPacketStream origin)
+{
+  SilcClientEntry client;
+  char *nicknamec = NULL;
+  char u[128], h[256];
+  int ret;
+
+  if (!id || !origin || !nickname || !username)
+    return NULL;
+
+  client = silc_calloc(1, sizeof(*client));
+  if (!client)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Adding client entry %p", client));
+
+  /* Normalize name.  This is cached, original is in client context.  */
+  nicknamec = silc_identifier_check(nickname, strlen(nickname),
+                                   SILC_STRING_UTF8, 128, NULL);
+  if (!nicknamec)
+    goto err;
+
+  /* Check username */
+  ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
+  if (!ret)
+    goto err;
+  if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
+    goto err;
+  if (ret == 2 &&
+      !silc_identifier_verify(h, strlen(h), SILC_STRING_UTF8, 256))
+    goto err;
+
+  client->nickname = strdup(nickname);
+  if (!client->nickname)
+    goto err;
+
+  client->username = strdup(username);
+  if (!client->username)
+    goto err;
+
+  client->userinfo = userinfo ? strdup(userinfo) : NULL;
+  if (!client->userinfo)
+    goto err;
+
+  client->id = *id;
+  client->mode = mode;
+  client->stream = origin;
+
+  client->channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL,
+                                          NULL, NULL, NULL, NULL, TRUE);
+  if (!client->channels)
+    goto err;
+
+  if (!silc_idcache_add(server->clients, nicknamec, (void *)&client->id,
+                       (void *)client))
+    goto err;
+
+  /* Take reference of the packet stream */
+  silc_packet_stream_ref(origin);
+
+  return client;
+
+ err:
+  if (client->channels)
+    silc_hash_table_free(client->channels);
+  silc_free(client->nickname);
+  silc_free(client->username);
+  silc_free(client->userinfo);
+  silc_free(client);
+  silc_free(nicknamec);
+  return NULL;
+}
+
+/* Delete client entry */
+
+SilcBool silc_server_del_client(SilcServer server, SilcClientEntry entry)
+{
+  SILC_LOG_DEBUG(("Deleting client %s id %s", entry->nickname ?
+                 entry->nickname : (unsigned char *)"??", &entry->id ?
+                 silc_id_render(&entry->id, SILC_ID_CLIENT) : "??"));
+
+  /* Delete */
+  if (!silc_idcache_del_by_context(server->clients, entry, NULL)) {
+    SILC_LOG_ERROR(("Unknown client %s, could not delete from cache",
+                   &entry->id ? silc_id_render(&entry->id, SILC_ID_CLIENT) :
+                   "??"));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Finds all clients matching the nickanem `nickname'.  Returns list of
+   SilcIDCacheEntry entries.  The `nickname' must be normalized. */
+
+SilcBool silc_server_find_clients(SilcServer server, char *nickname,
+                                 SilcList *list)
+{
+  SilcClientID client_id;
+  unsigned char hash[16];
+
+  SILC_LOG_DEBUG(("Find clients named %s", nickname));
+
+  /* Find using Client ID hash, as Client ID is based on the nickname,
+     we can find clients quickly using the hash of the nickname. */
+  memset(&client_id, 0, sizeof(client_id));
+  silc_hash_make(server->md5hash, nickname, strlen(nickname), hash);
+  memcpy(client_id.hash, hash, CLIENTID_HASH_LEN);
+
+  if (!silc_idcache_find_by_id(server->clients, &client_id, list))
+    return FALSE;
+
+  SILC_LOG_DEBUG(("Found %d clients", silc_list_count(*list)));
+
+  return TRUE;
+}
+
+/* Finds client by Client ID */
+
+SilcClientEntry silc_server_find_client_by_id(SilcServer server,
+                                             SilcClientID *id,
+                                             SilcBool registered,
+                                             SilcIDCacheEntry *ret_entry)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client;
+
+  if (!id)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Client ID (%s)", silc_id_render(id, SILC_ID_CLIENT)));
+
+  if (!silc_idcache_find_by_id_one(server->clients, (void *)id, &id_cache))
+    return NULL;
+
+  client = id_cache->context;
+
+  if (client && registered && !(client->data.registered))
+    return NULL;
+
+  if (ret_entry)
+    *ret_entry = id_cache;
+
+  SILC_LOG_DEBUG(("Found"));
+
+  return client;
+}
+
+/* Replaces old Client ID with new one */
+
+SilcClientEntry
+silc_server_replace_client_id(SilcServer server, SilcClientID *old_id,
+                             SilcClientID *new_id, const char *nickname)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry entry;
+  char *name, *nicknamec = NULL;
+
+  if (!old_id || !new_id)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Replacing Client ID %s",
+                 silc_id_render(old_id, SILC_ID_SERVER)));
+  SILC_LOG_DEBUG(("New Client ID %s",
+                 silc_id_render(new_id, SILC_ID_SERVER)));
+
+  /* Normalize name. This is cached, original is in client context.  */
+  if (nickname) {
+    nicknamec = silc_identifier_check(nickname, strlen(nickname),
+                                     SILC_STRING_UTF8, 128, NULL);
+    if (!nicknamec)
+      return NULL;
+  }
+
+  if (!silc_idcache_find_by_id_one(server->clients, (void *)old_id,
+                                  &id_cache))
+    return NULL;
+
+  entry = id_cache->context;
+  entry->id = *new_id;
+
+  name = id_cache->name;
+  if (!silc_idcache_update(server->clients, id_cache, old_id, &entry->id,
+                          name, nicknamec)) {
+    SILC_LOG_ERROR(("Error updating Client ID"));
+    return NULL;
+  }
+  if (nicknamec)
+    silc_free(name);
+
+  /* Check if anyone is watching old nickname */
+  if (server->server_type == SILC_ROUTER)
+    silc_server_check_watcher_list(server, entry, nickname,
+                                  SILC_NOTIFY_TYPE_NICK_CHANGE);
+
+  silc_free(entry->nickname);
+  entry->nickname = nickname ? strdup(nickname) : NULL;
+
+  /* Check if anyone is watching new nickname */
+  if (server->server_type == SILC_ROUTER)
+    silc_server_check_watcher_list(server, entry, nickname,
+                                  SILC_NOTIFY_TYPE_NICK_CHANGE);
+
+  SILC_LOG_DEBUG(("Replaced"));
+
+  return entry;
+}
+
+
+/****************************** Channel entry *******************************/
+
+void silc_server_destructor_channel(SilcIDCache cache,
+                                   const SilcIDCacheEntry entry,
+                                   void *destructor_context,
+                                   void *app_context)
+{
+
+}
+
+/* Add new channel */
+
+SilcChannelEntry silc_server_add_channel(SilcServer server,
+                                        const char *channel_name,
+                                        SilcUInt32 mode,
+                                        SilcChannelID *id,
+                                        SilcPacketStream origin,
+                                        SilcCipher channel_key,
+                                        SilcHmac hmac)
+{
+  SilcChannelEntry channel;
+  char *channel_namec = NULL;
+
+  if (!id || !channel_key || !hmac)
+    return NULL;
+
+  channel = silc_calloc(1, sizeof(*channel));
+  if (!channel)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Adding new channel %s %p", channel_name, channel));
+
+  /* Normalize name.  This is cached, original is in client context.  */
+  if (channel_name) {
+    channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
+                                           SILC_STRING_UTF8, 256, NULL);
+    if (!channel_namec) {
+      silc_free(channel);
+      return NULL;
+    }
+  }
+
+  channel->channel_name = channel_name ? strdup(channel_name) : NULL;
+  if (!channel) {
+      silc_free(channel);
+      silc_free(channel_namec);
+      return NULL;
+  }
+
+  channel->mode = mode;
+  channel->id = *id;
+  channel->channel_key = channel_key;
+  channel->hmac = hmac;
+  channel->router = origin;
+
+  channel->user_list = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL,
+                                            NULL, NULL, NULL, TRUE);
+  if (!channel->user_list) {
+    silc_cipher_free(channel->channel_key);
+    silc_hmac_free(channel->hmac);
+    silc_free(channel->channel_name);
+    silc_free(channel);
+    silc_free(channel_namec);
+    return NULL;
+  }
+
+  if (!silc_idcache_add(server->channels, channel_namec,
+                       (void *)&channel->id, (void *)channel)) {
+    silc_cipher_free(channel->channel_key);
+    silc_hmac_free(channel->hmac);
+    silc_free(channel->channel_name);
+    silc_hash_table_free(channel->user_list);
+    silc_free(channel);
+    silc_free(channel_namec);
+    return NULL;
+  }
+
+  /* Take reference of the packet stream */
+  silc_packet_stream_ref(origin);
+
+  return channel;
+}
+
+/* Free channel entry.  This free's everything. */
+
+SilcBool silc_server_del_channel(SilcServer server, SilcChannelEntry entry)
+{
+  SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
+
+  /* Remove from cache */
+  if (!silc_idcache_del_by_context(server->channels, entry, NULL)) {
+    SILC_LOG_DEBUG(("Unknown channel %s, did not delete",
+                   entry->channel_name));
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/* Finds channel by channel name.  Channel names are unique and they
+   are not case-sensitive.  The 'name' must be normalized already. */
+
+SilcChannelEntry silc_server_find_channel_by_name(SilcServer server,
+                                                 const char *name,
+                                                 SilcIDCacheEntry *ret_entry)
+{
+  SilcIDCacheEntry id_cache = NULL;
+
+  SILC_LOG_DEBUG(("Channel by name %s", name));
+
+  if (!silc_idcache_find_by_name_one(server->channels, (char *)name,
+                                    &id_cache))
+    return NULL;
+
+  if (ret_entry)
+    *ret_entry = id_cache;
+
+  SILC_LOG_DEBUG(("Found"));
+
+  return id_cache->context;
+}
+
+/* Finds channel by Channel ID. */
+
+SilcChannelEntry silc_server_find_channel_by_id(SilcServer server,
+                                               SilcChannelID *id,
+                                               SilcIDCacheEntry *ret_entry)
+{
+  SilcIDCacheEntry id_cache = NULL;
+
+  if (!id)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Channel ID (%s)", silc_id_render(id, SILC_ID_CHANNEL)));
+
+  if (!silc_idcache_find_by_id_one(server->channels, (void *)id, &id_cache))
+    return NULL;
+
+  if (ret_entry)
+    *ret_entry = id_cache;
+
+  SILC_LOG_DEBUG(("Found"));
+
+  return id_cache->context;
+}
+
+/* Replaces old Channel ID with new one. This is done when router forces
+   normal server to change Channel ID. */
+
+SilcChannelEntry silc_server_replace_channel_id(SilcServer server,
+                                               SilcChannelID *old_id,
+                                               SilcChannelID *new_id)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry entry;
+
+  if (!old_id || !new_id)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Replacing Channel ID %s",
+                 silc_id_render(old_id, SILC_ID_CHANNEL)));
+  SILC_LOG_DEBUG(("New Channel ID %s",
+                 silc_id_render(new_id, SILC_ID_CHANNEL)));
+
+  if (!silc_idcache_find_by_id_one(server->channels, (void *)old_id,
+                                  &id_cache))
+    return NULL;
+
+  entry = id_cache->context;
+  entry->id = *new_id;
+
+  if (!silc_idcache_update(server->channels, id_cache, old_id, &entry->id,
+                          NULL, NULL)) {
+    SILC_LOG_ERROR(("Error updating Channel ID"));
+    return NULL;
+  }
+
+  SILC_LOG_DEBUG(("Replaced"));
+
+  return entry;
+}
+
+/* Returns channels from the ID list.  If the `channel_id' is NULL then
+   all channels are returned.  Returns list of SilcIDCacheEntry entries. */
+
+SilcBool silc_server_get_channels(SilcServer server,
+                                 SilcChannelID *channel_id,
+                                 SilcList *list)
+{
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!channel_id) {
+    if (!silc_idcache_get_all(server->channels, list))
+      return FALSE;
+  } else {
+    if (!silc_idcache_find_by_id(server->channels, channel_id, list))
+      return FALSE;
+  }
+
+  return TRUE;
+}
diff --git a/lib/silcserver/server_entry.h b/lib/silcserver/server_entry.h
new file mode 100644 (file)
index 0000000..c4583d2
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+
+  server_entry.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SERVER_ENTRY_H
+#define SERVER_ENTRY_H
+
+void silc_server_destructor_client(SilcIDCache cache,
+                                  const SilcIDCacheEntry entry,
+                                  void *destructor_context,
+                                  void *app_context);
+void silc_server_destructor_server(SilcIDCache cache,
+                                  const SilcIDCacheEntry entry,
+                                  void *destructor_context,
+                                  void *app_context);
+void silc_server_destructor_channel(SilcIDCache cache,
+                                   const SilcIDCacheEntry entry,
+                                   void *destructor_context,
+                                   void *app_context);
+
+SilcServerEntry silc_server_add_server(SilcServer server,
+                                      const char *server_name,
+                                      SilcServerType server_type,
+                                      SilcServerID *id,
+                                      SilcPacketStream origin);
+SilcBool silc_server_del_server(SilcServer server, SilcServerEntry entry);
+SilcServerEntry
+silc_server_find_server_by_id(SilcServer server,
+                             SilcServerID *id,
+                             SilcBool registered,
+                             SilcIDCacheEntry *ret_entry);
+SilcServerEntry
+silc_server_find_server_by_name(SilcServer server, char *name,
+                               SilcBool registered,
+                               SilcIDCacheEntry *ret_entry);
+SilcServerEntry
+silc_server_find_server_by_conn(SilcServer server, char *hostname,
+                               int port, SilcBool registered,
+                               SilcIDCacheEntry *ret_entry);
+SilcServerEntry
+silc_server_replace_server_id(SilcServer server, SilcServerID *old_id,
+                             SilcServerID *new_id);
+SilcClientEntry silc_server_add_client(SilcServer server,
+                                      const char *nickname,
+                                      const char *username,
+                                      const char *userinfo,
+                                      SilcClientID *id,
+                                      SilcUInt32 mode,
+                                      SilcPacketStream origin);
+SilcBool silc_server_del_client(SilcServer server, SilcClientEntry entry);
+SilcBool silc_server_find_clients(SilcServer server, char *nickname,
+                                 SilcList *list);
+SilcClientEntry silc_server_find_client_by_id(SilcServer server,
+                                             SilcClientID *id,
+                                             SilcBool registered,
+                                             SilcIDCacheEntry *ret_entry);
+SilcClientEntry
+silc_server_replace_client_id(SilcServer server, SilcClientID *old_id,
+                             SilcClientID *new_id, const char *nickname);
+SilcChannelEntry silc_server_add_channel(SilcServer server,
+                                        const char *channel_name,
+                                        SilcUInt32 mode,
+                                        SilcChannelID *id,
+                                        SilcPacketStream origin,
+                                        SilcCipher channel_key,
+                                        SilcHmac hmac);
+SilcBool silc_server_del_channel(SilcServer server, SilcChannelEntry entry);
+SilcChannelEntry silc_server_find_channel_by_name(SilcServer server,
+                                                 const char *name,
+                                                 SilcIDCacheEntry *ret_entry);
+SilcChannelEntry silc_server_find_channel_by_id(SilcServer server,
+                                               SilcChannelID *id,
+                                               SilcIDCacheEntry *ret_entry);
+SilcChannelEntry silc_server_replace_channel_id(SilcServer server,
+                                               SilcChannelID *old_id,
+                                               SilcChannelID *new_id);
+SilcBool silc_server_get_channels(SilcServer server,
+                                 SilcChannelID *channel_id,
+                                 SilcList *list);
+
+#endif /* SERVER_ENTRY_H */
diff --git a/lib/silcserver/server_params.c b/lib/silcserver/server_params.c
new file mode 100644 (file)
index 0000000..8b8052d
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+
+  server_params.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/************************** Types and definitions ***************************/
+
+/* Default values */
+#define SILC_SERVER_PARAM_RETRY_COUNT        7   /* Max retry count */
+#define SILC_SERVER_PARAM_RETRY_MULTIPLIER   2   /* Interval growth */
+#define SILC_SERVER_PARAM_RETRY_RANDOMIZER   2   /* timeout += rnd % 2 */
+#define SILC_SERVER_PARAM_RETRY_INTERVAL_MIN 10          /* Min retry timeout */
+#define SILC_SERVER_PARAM_RETRY_INTERVAL_MAX 600  /* Max generated timeout */
+#define SILC_SERVER_PARAM_REKEY              3600 /* Session rekey interval */
+#define SILC_SERVER_PARAM_KEEPALIVE          300  /* Heartbeat interval */
+#define SILC_SERVER_PARAM_MAX_CONNS          1000 /* Max connections */
+#define SILC_SERVER_PARAM_MAX_CONNS_SINGLE   1000 /* Max conns per host */
+#define SILC_SERVER_PARAM_CONN_PER_THREAD    30          /* Connections per thread */
+#define SILC_SERVER_PARAM_CHANNEL_REKEY      3600 /* Channel rekey interval */
+#define SILC_SERVER_PARAM_SKE_TIMEOUT        60          /* SKE timeout */
+#define SILC_SERVER_PARAM_CONNAUTH_TIMEOUT   60          /* CONN_AUTH timeout */
+#define SILC_SERVER_PARAM_QOS_RATE_LIMIT     10          /* QoS rate limit */
+#define SILC_SERVER_PARAM_QOS_BYTES_LIMIT    2048 /* QoS bytes limit */
+#define SILC_SERVER_PARAM_QOS_LIMIT_SEC      0    /* QoS limit sec */
+#define SILC_SERVER_PARAM_QOS_LIMIT_USEC     500000 /* QoS limit usec */
+#define SILC_SERVER_PARAM_CH_JOIN_LIMIT      50          /* Join limit */
+
+
+/************************ Static utility functions **************************/
+
+/* Sets connection parameter defaults */
+
+static void
+silc_server_param_set_param_defaults(SilcServerParamConnParams params,
+                                    SilcServerParamConnParams defaults)
+{
+#define SET_PARAM_DEFAULT(p, d)        params->p =                             \
+  (params->p ? params->p : (defaults && defaults->p ? defaults->p : d))
+
+  SET_PARAM_DEFAULT(connections_max, SILC_SERVER_PARAM_MAX_CONNS);
+  SET_PARAM_DEFAULT(connections_max_per_host,
+                   SILC_SERVER_PARAM_MAX_CONNS_SINGLE);
+  SET_PARAM_DEFAULT(keepalive_secs, SILC_SERVER_PARAM_KEEPALIVE);
+  SET_PARAM_DEFAULT(reconnect_count, SILC_SERVER_PARAM_RETRY_COUNT);
+  SET_PARAM_DEFAULT(reconnect_interval, SILC_SERVER_PARAM_RETRY_INTERVAL_MIN);
+  SET_PARAM_DEFAULT(reconnect_interval_max,
+                   SILC_SERVER_PARAM_RETRY_INTERVAL_MAX);
+  SET_PARAM_DEFAULT(key_exchange_rekey, SILC_SERVER_PARAM_REKEY);
+  SET_PARAM_DEFAULT(qos_rate_limit, SILC_SERVER_PARAM_QOS_RATE_LIMIT);
+  SET_PARAM_DEFAULT(qos_bytes_limit, SILC_SERVER_PARAM_QOS_BYTES_LIMIT);
+  SET_PARAM_DEFAULT(qos_limit_sec, SILC_SERVER_PARAM_QOS_LIMIT_SEC);
+  SET_PARAM_DEFAULT(qos_limit_usec, SILC_SERVER_PARAM_QOS_LIMIT_USEC);
+  SET_PARAM_DEFAULT(chlimit, SILC_SERVER_PARAM_CH_JOIN_LIMIT);
+
+#undef SET_PARAM_DEFAULT
+}
+
+
+/***************************** Retrieval API ********************************/
+
+/* Returns the denied connection configuration entry by host. */
+
+SilcServerParamDeny
+silc_server_params_find_denied(SilcServer server, char *ip, char *host)
+{
+  SilcServerParams params = server->params;
+  SilcServerParamDeny deny;
+
+  if (ip) {
+    silc_list_start(params->denied);
+    while ((deny = silc_list_get(params->denied)) != SILC_LIST_END) {
+      if (deny->host && !silc_string_compare(deny->host, ip))
+       continue;
+      return deny;
+    }
+  }
+
+  if (host) {
+    silc_list_start(params->denied);
+    while ((deny = silc_list_get(params->denied)) != SILC_LIST_END) {
+      if (deny->host && !silc_string_compare(deny->host, host))
+       continue;
+      return deny;
+    }
+  }
+
+  return NULL;
+}
+
+/* Returns client connection information from configuration file by host
+   (name or ip) */
+
+SilcServerParamClient
+silc_server_params_find_client(SilcServer server, char *ip, char *host)
+{
+  SilcServerParams params = server->params;
+  SilcServerParamClient client;
+
+  if (ip) {
+    silc_list_start(params->clients);
+    while ((client = silc_list_get(params->clients)) != SILC_LIST_END) {
+      if (client->host && !silc_string_compare(client->host, ip))
+       continue;
+      return client;
+    }
+  }
+
+  if (host) {
+    silc_list_start(params->clients);
+    while ((client = silc_list_get(params->clients)) != SILC_LIST_END) {
+      if (client->host && !silc_string_compare(client->host, host))
+       continue;
+      return client;
+    }
+  }
+
+  return NULL;
+}
+
+/* Returns server connection info from server configuartion by host
+   (name or ip). */
+
+SilcServerParamServer
+silc_server_params_find_server(SilcServer server, char *ip, char *host)
+{
+  SilcServerParams params = server->params;
+  SilcServerParamServer serv;
+
+  if (ip) {
+    silc_list_start(params->servers);
+    while ((serv = silc_list_get(params->servers)) != SILC_LIST_END) {
+      if (serv->host && !silc_string_compare(serv->host, ip))
+       continue;
+      return serv;
+    }
+  }
+
+  if (host) {
+    silc_list_start(params->servers);
+    while ((serv = silc_list_get(params->servers)) != SILC_LIST_END) {
+      if (serv->host && !silc_string_compare(serv->host, host))
+       continue;
+      return serv;
+    }
+  }
+
+  return NULL;
+}
+
+/* Returns router connection info from server configuration by
+   host (name or ip). */
+
+SilcServerParamRouter
+silc_server_params_find_router(SilcServer server, char *ip,
+                              char *host, int port)
+{
+  SilcServerParams params = server->params;
+  SilcServerParamRouter serv;
+
+  if (ip) {
+    silc_list_start(params->routers);
+    while ((serv = silc_list_get(params->routers)) != SILC_LIST_END) {
+      if (serv->host && !silc_string_compare(serv->host, ip))
+       continue;
+      if (port && serv->port && serv->port != port)
+       continue;
+      return serv;
+    }
+  }
+
+  if (host) {
+    silc_list_start(params->routers);
+    while ((serv = silc_list_get(params->routers)) != SILC_LIST_END) {
+      if (serv->host && !silc_string_compare(serv->host, host))
+        continue;
+      if (port && serv->port && serv->port != port)
+       continue;
+      return serv;
+    }
+  }
+
+  return NULL;
+}
+
+/* Find backup router connection by host (name or ip) */
+
+SilcServerParamRouter
+silc_server_params_find_backup(SilcServer server, char *host, char *ip)
+{
+  SilcServerParams params = server->params;
+  SilcServerParamRouter serv;
+
+  if (ip) {
+    silc_list_start(params->routers);
+    while ((serv = silc_list_get(params->routers)) != SILC_LIST_END) {
+      if (!serv->backup_router)
+       continue;
+      if (!silc_string_compare(serv->host, ip))
+       continue;
+      return serv;
+    }
+  }
+
+  if (host) {
+    silc_list_start(params->routers);
+    while ((serv = silc_list_get(params->routers)) != SILC_LIST_END) {
+      if (!serv->backup_router)
+       continue;
+      if (!silc_string_compare(serv->host, host))
+        continue;
+      return serv;
+    }
+  }
+
+  return NULL;
+}
+
+
+/******************************* Public API *********************************/
+
+/* Allocate parameters context */
+
+SilcServerParams silc_server_params_alloc(void)
+{
+  SilcServerParams params;
+
+  params = silc_calloc(1, sizeof(*params));
+  if (!params)
+    return NULL;
+
+  /* Init lists */
+  silc_list_init(params->cipher, struct SilcServerParamCipherStruct, next);
+  silc_list_init(params->hash, struct SilcServerParamHashStruct, next);
+  silc_list_init(params->hmac, struct SilcServerParamHmacStruct, next);
+  silc_list_init(params->pkcs, struct SilcServerParamPkcsStruct, next);
+  silc_list_init(params->clients, struct SilcServerParamClientStruct, next);
+  silc_list_init(params->servers, struct SilcServerParamServerStruct, next);
+  silc_list_init(params->routers, struct SilcServerParamRouterStruct, next);
+  silc_list_init(params->conn_params, SilcServerParamConnParamsStruct, next);
+  silc_list_init(params->denied, struct SilcServerParamDenyStruct, next);
+  silc_list_init(params->admins, struct SilcServerParamAdminStruct, next);
+
+  /* Set default values */
+  silc_server_param_set_param_defaults(&params->param, NULL);
+  params->channel_rekey_secs = SILC_SERVER_PARAM_CHANNEL_REKEY;
+  params->key_exchange_timeout = SILC_SERVER_PARAM_SKE_TIMEOUT;
+  params->conn_auth_timeout = SILC_SERVER_PARAM_CONNAUTH_TIMEOUT;
+  params->connections_per_thread = SILC_SERVER_PARAM_CONN_PER_THREAD;
+
+  return params;
+}
+
+/* Frees parameters context */
+
+void silc_server_params_free(SilcServerParams params)
+{
+  silc_free(params);
+}
+
+/* Allocate server info context */
+
+SilcServerParamServerInfo silc_server_params_serverinfo_alloc(void)
+{
+  SilcServerParamServerInfo server_info;
+
+  server_info = silc_calloc(1, sizeof(*server_info));
+  if (!server_info)
+    return NULL;
+
+  silc_list_init(server_info->interfaces,
+                struct SilcServerParamInterfaceStruct, next);
+
+  return server_info;
+}
+
+/* Set server info */
+
+void silc_server_params_set_serverinfo(SilcServerParams params,
+                                      SilcServerParamServerInfo server_info)
+{
+  params->server_info = server_info;
+}
+
+/* Add interface */
+
+void silc_server_params_serverinfo_add_iface(SilcServerParamServerInfo info,
+                                            SilcServerParamInterface iface)
+{
+  silc_list_add(info->interfaces, iface);
+}
+
+/* Add cipher */
+
+void silc_server_params_add_cipher(SilcServerParams params,
+                                  SilcServerParamCipher cipher)
+{
+  silc_list_add(params->cipher, cipher);
+}
+
+/* Add hash */
+
+void silc_server_params_add_hash(SilcServerParams params,
+                                SilcServerParamHash hash)
+{
+  silc_list_add(params->hash, hash);
+}
+
+/* Add HMAC */
+
+void silc_server_params_add_hmac(SilcServerParams params,
+                                SilcServerParamHmac hmac)
+{
+  silc_list_add(params->hmac, hmac);
+}
+
+/* Add PKCS */
+
+void silc_server_params_add_pkcs(SilcServerParams params,
+                                SilcServerParamPkcs pkcs)
+{
+  silc_list_add(params->pkcs, pkcs);
+}
+
+/* Add client */
+
+void silc_server_params_add_client(SilcServerParams params,
+                                  SilcServerParamClient client)
+{
+  silc_list_add(params->clients, client);
+}
+
+/* Add server */
+
+void silc_server_params_add_server(SilcServerParams params,
+                                  SilcServerParamServer server)
+{
+  silc_list_add(params->servers, server);
+}
+
+/* Add router */
+
+void silc_server_params_add_router(SilcServerParams params,
+                                  SilcServerParamRouter router)
+{
+  silc_list_add(params->routers, router);
+}
+
+/* Add connection parameters */
+
+void silc_server_params_add_connparam(SilcServerParams params,
+                                     SilcServerParamConnParams param)
+{
+  silc_list_add(params->conn_params, param);
+}
+
+/* Add deny */
+
+void silc_server_params_add_deny(SilcServerParams params,
+                                SilcServerParamDeny deny)
+{
+  silc_list_add(params->denied, deny);
+}
+
+/* Add admin */
+
+void silc_server_params_add_admin(SilcServerParams params,
+                                 SilcServerParamAdmin admin)
+{
+  silc_list_add(params->admins, admin);
+}
diff --git a/lib/silcserver/server_send.c b/lib/silcserver/server_send.c
new file mode 100644 (file)
index 0000000..9ec759d
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+
+  server_send.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+/* $Id: */
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/******************************* Heartbeat **********************************/
+
+/* Send the heartbeat packet. */
+
+SilcBool silc_server_send_heartbeat(SilcPacketStream stream)
+{
+  return stream ? silc_packet_send(stream, SILC_PACKET_HEARTBEAT, 0,
+                                  NULL, 0) : FALSE;
+}
+
+
+/********************************* Error ************************************/
+
+/* Sends error packet. */
+
+SilcBool silc_server_send_error(SilcPacketStream stream, const char *fmt, ...)
+{
+  unsigned char buf[2048];
+  va_list ap;
+
+  if (!stream)
+    return FALSE;
+
+  memset(buf, 0, sizeof(buf));
+  va_start(ap, fmt);
+  vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
+  va_end(ap);
+
+  return silc_packet_send(stream, SILC_PACKET_ERROR, 0, buf, strlen(buf));
+}
+
+
+/********************************* New ID ***********************************/
+
+/* Sends New ID packet.  The packet is used to distribute information about
+   new registered clients, servers and channels.  If the argument `broadcast'
+   is TRUE then the packet is sent as broadcast packet. */
+
+SilcBool silc_server_send_new_id(SilcPacketStream stream,
+                                SilcBool broadcast,
+                                void *id, SilcIdType id_type)
+{
+  SilcBuffer idp;
+  SilcBool ret = FALSE;
+
+  if (!stream || !id)
+    return ret;
+
+  SILC_LOG_DEBUG(("Sending new ID (%s)", silc_id_render(id, id_type)));
+
+  idp = silc_id_payload_encode(id, id_type);
+  if (!idp)
+    return ret;
+
+  ret = silc_packet_send(stream, SILC_PACKET_NEW_ID,
+                        broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+                        idp->data, silc_buffer_len(idp));
+
+  silc_buffer_free(idp);
+  return ret;
+}
+
+
+/****************************** Notify packets ******************************/
+
+/* Sends notify packet.  Each variable argument format in the argument list
+   must be { argument data, argument length }. */
+
+SilcBool silc_server_send_notify(SilcServer server,
+                                SilcPacketStream stream,
+                                SilcBool broadcast,
+                                SilcNotifyType type,
+                                SilcUInt32 argc, ...)
+{
+  va_list ap;
+  SilcBuffer packet;
+  SilcBool ret = FALSE;
+
+  if (!stream)
+    return FALSE;
+
+  va_start(ap, argc);
+
+  packet = silc_notify_payload_encode(type, argc, ap);
+  if (!packet) {
+    va_end(ap);
+    return ret;
+  }
+
+  ret = silc_packet_send(stream, SILC_PACKET_NOTIFY,
+                        broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+                        packet->data, silc_buffer_len(packet));
+
+#if 0
+  /* Send to backup routers if this is being broadcasted to primary
+     router.  The silc_server_backup_send checks further whether to
+     actually send it or not. */
+  if ((broadcast && stream == SILC_PRIMARY_ROUTE(server)) ||
+      (broadcast && !SILC_PRIMARY_ROUTE(server)))
+    silc_server_backup_send(server, NULL, SILC_PACKET_NOTIFY, 0,
+                           packet->data, packet->len, FALSE, TRUE);
+#endif /* 0 */
+
+  silc_buffer_free(packet);
+  va_end(ap);
+
+  return ret;
+}
+
+/* Sends current motd to client in notify packet */
+
+SilcBool silc_server_send_motd(SilcServer server, SilcPacketStream stream)
+{
+  char *motd, *motd_file = NULL;
+  SilcUInt32 motd_len;
+  SilcBool ret = FALSE;
+
+  if (!stream || !server->params)
+    return FALSE;
+
+  motd_file = server->params->server_info->motd_file;
+  if (!motd_file)
+    return FALSE;
+
+  motd = silc_file_readfile(motd_file, &motd_len);
+  if (!motd)
+    return FALSE;
+
+  motd[motd_len] = 0;
+  ret = silc_server_send_notify(server, stream, FALSE,
+                               SILC_NOTIFY_TYPE_MOTD, 1, motd, motd_len);
+  silc_free(motd);
+
+  return ret;
+}
+
+
+/* Sends notify packet and gets the arguments from the `args' Argument
+   Payloads. */
+
+SilcBool silc_server_send_notify_args(SilcPacketStream stream,
+                                     SilcBool broadcast,
+                                     SilcNotifyType type,
+                                     SilcUInt32 argc,
+                                     SilcBuffer args)
+{
+  SilcBuffer packet;
+  SilcBool ret = FALSE;
+
+  if (!stream)
+    return FALSE;
+
+  packet = silc_notify_payload_encode_args(type, argc, args);
+  if (!packet)
+    return ret;
+
+  ret = silc_packet_send(stream, SILC_PACKET_NOTIFY,
+                        broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
+                        packet->data, silc_buffer_len(packet));
+
+  silc_buffer_free(packet);
+  return ret;
+}
+
+/* Send CHANNEL_CHANGE notify type. This tells the receiver to replace the
+   `old_id' with the `new_id'. */
+
+SilcBool silc_server_send_notify_channel_change(SilcServer server,
+                                               SilcPacketStream stream,
+                                               SilcBool broadcast,
+                                               SilcChannelID *old_id,
+                                               SilcChannelID *new_id)
+{
+  SilcBuffer idp1, idp2;
+  SilcBool ret = FALSE;
+
+  if (!server || !stream)
+    return ret;
+
+  idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CHANNEL);
+  idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CHANNEL);
+  if (!idp1 || !idp2)
+    return ret;
+
+  ret = silc_server_send_notify(server, stream, broadcast,
+                               SILC_NOTIFY_TYPE_CHANNEL_CHANGE,
+                               2, idp1->data, silc_buffer_len(idp1),
+                               idp2->data, silc_buffer_len(idp2));
+  silc_buffer_free(idp1);
+  silc_buffer_free(idp2);
+
+  return ret;
+}
diff --git a/lib/silcserver/server_st_accept.c b/lib/silcserver/server_st_accept.c
new file mode 100644 (file)
index 0000000..38e4acd
--- /dev/null
@@ -0,0 +1,991 @@
+/*
+
+  server_st_accept.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/************************ Static utility functions **************************/
+
+/* SKE public key verification callback */
+
+static void
+silc_server_accept_verify_key(SilcSKE ske,
+                             const unsigned char *pk_data,
+                             SilcUInt32 pk_len,
+                             SilcSKEPKType pk_type,
+                             void *context,
+                             SilcSKEVerifyCbCompletion completion,
+                             void *completion_context)
+{
+  SilcServerAccept ac = context;
+
+  SILC_LOG_DEBUG(("Verifying public key"));
+
+  if (pk_type != SILC_SKE_PK_TYPE_SILC) {
+    SILC_LOG_WARNING(("We don't support %s (%s) port %d public key type %d",
+                     ac->hostname, ac->ip, ac->port, pk_type));
+    completion(ac->data.ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
+              completion_context);
+    return;
+  }
+
+  /* We accept all keys without explicit verification */
+  completion(ac->data.ske, SILC_SKE_STATUS_OK, completion_context);
+}
+
+/* SKE completion callback */
+
+static void
+silc_server_accept_completed(SilcSKE ske, SilcSKEStatus status,
+                            SilcSKESecurityProperties prop,
+                            SilcSKEKeyMaterial keymat,
+                            SilcSKERekeyMaterial rekey,
+                            void *context)
+{
+  SilcServerAccept ac = context;
+
+  ac->status = status;
+  ac->prop = prop;
+  ac->keymat = keymat;
+  ac->rekey = rekey;
+
+  /* Continue synchronously to take keys into use immediately */
+  SILC_FSM_CALL_CONTINUE_SYNC(ac->t);
+}
+
+/* Authentication data callback */
+
+static SilcBool
+silc_server_accept_get_auth(SilcConnAuth connauth,
+                           SilcConnectionType conn_type,
+                           unsigned char **passphrase,
+                           SilcUInt32 *passphrase_len,
+                           SilcSKR *repository,
+                           void *context)
+{
+  SilcServerAccept ac = context;
+
+  SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
+
+  /* Remote end is client */
+  if (conn_type == SILC_CONN_CLIENT) {
+    if (!ac->cconfig)
+      return FALSE;
+
+    *passphrase = ac->cconfig->passphrase;
+    *passphrase_len = ac->cconfig->passphrase_len;
+    if (ac->cconfig->pubkey_auth)
+      *repository = ac->thread->server->repository;
+  }
+
+  /* Remote end is server */
+  if (conn_type == SILC_CONN_SERVER) {
+    if (!ac->sconfig)
+      return FALSE;
+
+    *passphrase = ac->sconfig->passphrase;
+    *passphrase_len = ac->sconfig->passphrase_len;
+    if (ac->sconfig->pubkey_auth)
+      *repository = ac->thread->server->repository;
+  }
+
+  /* Remote end is router */
+  if (conn_type == SILC_CONN_ROUTER) {
+    if (!ac->rconfig)
+      return FALSE;
+
+    *passphrase = ac->rconfig->passphrase;
+    *passphrase_len = ac->rconfig->passphrase_len;
+    if (ac->rconfig->pubkey_auth)
+      *repository = ac->thread->server->repository;
+  }
+
+  ac->data.type = conn_type;
+
+  return TRUE;
+}
+
+/* Authentication completion callback */
+
+static void
+silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success,
+                             void *context)
+{
+  SilcServerAccept ac = context;
+  ac->auth_success = success;
+  SILC_FSM_CALL_CONTINUE(ac->t);
+}
+
+/* Free context */
+
+static void silc_server_accept_free(SilcServerAccept ac)
+{
+  if (ac->connauth)
+    silc_connauth_free(ac->connauth);
+  silc_free(ac->error_string);
+  silc_free(ac);
+}
+
+void silc_server_accept_connection_dest(SilcFSM fsm, void *fsm_context,
+                                       void *destructor_context)
+{
+  SilcServerAccept ac = fsm_context;
+  silc_fsm_free(fsm);
+  silc_server_accept_free(ac);
+}
+
+
+/********************* Accepting new connection thread **********************/
+
+SILC_FSM_STATE(silc_server_st_accept_connection)
+{
+  SilcServerAccept ac = fsm_context;
+  SilcServer server = ac->thread->server;
+  SilcServerParamDeny deny;
+  SilcSKESecurityPropertyFlag flags = 0;
+
+  SILC_LOG_DEBUG(("Accepting new connection"));
+
+  /* Create packet stream */
+  ac->packet_stream = silc_packet_stream_create(ac->thread->packet_engine,
+                                               silc_fsm_get_schedule(fsm),
+                                               ac->stream);
+  if (!ac->packet_stream) {
+    /** Cannot create packet stream */
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  silc_packet_set_context(ac->packet_stream, ac);
+
+  /* Set source ID to packet stream */
+  if (!silc_packet_set_ids(ac->packet_stream, SILC_ID_SERVER, &server->id,
+                          0, NULL)) {
+    /** Out of memory */
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (!silc_socket_stream_get_info(ac->stream, NULL, &ac->hostname,
+                                  &ac->ip, &ac->port)) {
+    /** Bad socket stream */
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Check whether this connection is denied to connect to us. */
+  deny = silc_server_params_find_denied(server, ac->ip, ac->hostname);
+  if (deny) {
+    /** Connection is denied */
+    SILC_LOG_INFO(("Connection %s (%s) is denied", ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_BANNED_FROM_SERVER;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  server->params->refcnt++;
+
+  /* Check whether we have configured this sort of connection at all. We
+     have to check all configurations since we don't know what type of
+     connection this is. */
+  ac->cconfig = silc_server_params_find_client(server, ac->ip, ac->hostname);
+  ac->sconfig = silc_server_params_find_server(server, ac->ip, ac->hostname);
+  if (server->server_type == SILC_ROUTER)
+    ac->rconfig = silc_server_params_find_router(server, ac->ip,
+                                                ac->hostname, ac->port);
+  if (!ac->cconfig && !ac->sconfig && !ac->rconfig) {
+    /** Connection not configured */
+    SILC_LOG_INFO(("Connection %s (%s) not configured", ac->hostname,
+                  ac->ip));
+    ac->error = SILC_STATUS_ERR_BANNED_FROM_SERVER;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  SILC_LOG_INFO(("Incoming connection %s (%s)", ac->hostname, ac->ip));
+
+  /* Take flags for key exchange. Since we do not know what type of connection
+     this is, we go through all found configurations and use the global ones
+     as well. This will result always into strictest key exchange flags. */
+  SILC_GET_SKE_FLAGS(ac->cconfig, flags);
+  SILC_GET_SKE_FLAGS(ac->sconfig, flags);
+  SILC_GET_SKE_FLAGS(ac->rconfig, flags);
+  if (server->params->param.key_exchange_pfs)
+    flags |= SILC_SKE_SP_FLAG_PFS;
+
+  server->stat.conn_attempts++;
+
+  /* Start SILC Key Exchange protocol */
+  SILC_LOG_DEBUG(("Starting key exchange protocol"));
+  ac->data.ske = silc_ske_alloc(server->rng, silc_fsm_get_schedule(fsm),
+                               server->public_key, server->private_key, ac);
+  if (!ac->data.ske) {
+    /** Out of memory */
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+  silc_ske_set_callbacks(ac->data.ske, silc_server_accept_verify_key,
+                        silc_server_accept_completed, ac);
+
+  /** Waiting for SKE completion */
+  silc_fsm_next(fsm, silc_server_st_accept_set_keys);
+  SILC_FSM_CALL((ac->op = silc_ske_responder(ac->data.ske, ac->packet_stream,
+                                            silc_version_string, flags)));
+}
+
+SILC_FSM_STATE(silc_server_st_accept_set_keys)
+{
+  SilcServerAccept ac = fsm_context;
+  SilcServer server = ac->thread->server;
+  SilcCipher send_key, receive_key;
+  SilcHmac hmac_send, hmac_receive;
+
+  if (ac->status != SILC_SKE_STATUS_OK) {
+    /** SKE failed */
+    SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
+                   silc_ske_map_status(ac->status), ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_KEY_EXCHANGE_FAILED;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  SILC_LOG_DEBUG(("Setting keys into use"));
+
+  /* Set the keys into use.  The data will be encrypted after this. */
+  if (!silc_ske_set_keys(ac->data.ske, ac->keymat, ac->prop, &send_key,
+                        &receive_key, &hmac_send, &hmac_receive,
+                        &ac->hash)) {
+    /** Error setting keys */
+    ac->error = SILC_STATUS_ERR_KEY_EXCHANGE_FAILED;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+  silc_packet_set_ciphers(ac->packet_stream, send_key, receive_key);
+  silc_packet_set_hmacs(ac->packet_stream, hmac_send, hmac_receive);
+
+  SILC_LOG_DEBUG(("Starting connection authentication"));
+  server->stat.auth_attempts++;
+
+  ac->connauth = silc_connauth_alloc(silc_fsm_get_schedule(fsm), ac->data.ske,
+                                    server->params->conn_auth_timeout);
+  if (!ac->connauth) {
+    /** Error allocating auth protocol */
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /** Waiting authentication completion */
+  silc_fsm_next(fsm, silc_server_st_accept_authenticated);
+  SILC_FSM_CALL((ac->op = silc_connauth_responder(
+                                         ac->connauth,
+                                         silc_server_accept_get_auth,
+                                         silc_server_accept_auth_compl,
+                                         ac)));
+}
+
+SILC_FSM_STATE(silc_server_st_accept_authenticated)
+{
+  SilcServerAccept ac = fsm_context;
+  SilcServer server = ac->thread->server;
+  SilcUInt32 conn_number, num_sockets, max_hosts, max_per_host;
+  SilcUInt32 r_protocol_version, l_protocol_version;
+  SilcUInt32 r_software_version, l_software_version;
+  char *r_vendor_version = NULL, *l_vendor_version;
+  SilcServerParamConnParams params, global;
+  SilcBool backup_router = FALSE;
+
+  if (ac->auth_success == FALSE) {
+    /** Authentication failed */
+    SILC_LOG_INFO(("Authentication failed for %s (%s) [%s]",
+                  ac->hostname, ac->ip,
+                  SILC_CONNTYPE_STRING(ac->data.type)));
+    ac->error = SILC_STATUS_ERR_AUTH_FAILED;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  SILC_LOG_DEBUG(("Checking whether connection is allowed"));
+
+  global = &server->params->param;
+
+  if (ac->data.type == SILC_CONN_CLIENT) {
+    /** Accept client connection */
+    silc_fsm_next(fsm, silc_server_st_accept_client);
+    params = ac->cconfig->param;
+    conn_number = server->stat.my_clients;
+  } else if (ac->data.type == SILC_CONN_SERVER) {
+    /** Accept server connection */
+    silc_fsm_next(fsm, silc_server_st_accept_server);
+    params = ac->sconfig->param;
+    backup_router = ac->sconfig->backup_router;
+    conn_number = server->stat.my_servers;
+  } else {
+    /** Accept router connection */
+    silc_fsm_next(fsm, silc_server_st_accept_server);
+    params = ac->rconfig->param;
+    backup_router = ac->rconfig->backup_router;
+    conn_number = server->stat.my_routers;
+  }
+
+  silc_fsm_sema_init(&ac->wait_register, silc_fsm_get_machine(fsm), 0);
+
+  /* Check version */
+  l_protocol_version = silc_version_to_num(params && params->version_protocol ?
+                                          params->version_protocol :
+                                          global->version_protocol);
+  l_software_version = silc_version_to_num(params && params->version_software ?
+                                          params->version_software :
+                                          global->version_software);
+  l_vendor_version = (params && params->version_software_vendor ?
+                     params->version_software_vendor :
+                     global->version_software_vendor);
+
+  silc_ske_parse_version(ac->data.ske, &r_protocol_version, NULL,
+                        &r_software_version, NULL, &r_vendor_version);
+
+  /* Match protocol version */
+  if (l_protocol_version && r_protocol_version &&
+      r_protocol_version < l_protocol_version) {
+    /** Protocol version mismatch */
+    SILC_LOG_INFO(("Connection %s (%s) is too old version", ac->hostname,
+                  ac->ip));
+    ac->error = SILC_STATUS_ERR_BAD_VERSION;
+    ac->error_string = strdup("You support too old protocol version");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Match software version */
+  if (l_software_version && r_software_version &&
+      r_software_version < l_software_version) {
+    /** Software version mismatch */
+    SILC_LOG_INFO(("Connection %s (%s) is too old version", ac->hostname,
+                  ac->ip));
+    ac->error = SILC_STATUS_ERR_BAD_VERSION;
+    ac->error_string = strdup("You support too old software version");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Regex match vendor version */
+  if (l_vendor_version && r_vendor_version &&
+      !silc_string_match(l_vendor_version, r_vendor_version)) {
+    /** Vendor version mismatch */
+    SILC_LOG_INFO(("Connection %s (%s) is unsupported version", ac->hostname,
+                  ac->ip));
+    ac->error = SILC_STATUS_ERR_BAD_VERSION;
+    ac->error_string = strdup("Your software is not supported");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+  silc_free(r_vendor_version);
+
+  /* Check for maximum connections limit */
+  //  num_sockets = silc_server_num_sockets_by_ip(server, sock->ip, type);
+  max_hosts = (params ? params->connections_max : global->connections_max);
+  max_per_host = (params ? params->connections_max_per_host :
+                 global->connections_max_per_host);
+
+  if (max_hosts && conn_number >= max_hosts) {
+    /** Server is full */
+    SILC_LOG_INFO(("Server is full, closing %s (%s) connection", ac->hostname,
+                  ac->ip));
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    ac->error_string = strdup("Server is full, try again later");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* XXX */
+  num_sockets = 0;
+  if (num_sockets >= max_per_host) {
+    /** Too many connections */
+    SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
+                  ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    ac->error_string = strdup("Too many connections from your host");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* If we are waiting backup router connection, do not accept any other
+     connections. */
+  if (server->wait_backup && !backup_router) {
+    /** No backup established */
+    SILC_LOG_INFO(("Will not accept connections because we do "
+                  "not have backup router connection established"));
+    ac->error = SILC_STATUS_ERR_PERM_DENIED;
+    ac->error_string = strdup("We do not have connection to backup router "
+                             "established, try later");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* If we are backup router and this is incoming server connection
+     and we do not have connection to primary router, do not allow
+     the connection. */
+  if (server->server_type == SILC_BACKUP_ROUTER &&
+      ac->data.type == SILC_CONN_SERVER &&
+      !SILC_PRIMARY_ROUTE(server)) {
+    /** No primary established */
+    SILC_LOG_INFO(("Will not accept server connection because we do "
+                  "not have primary router connection established"));
+    ac->error = SILC_STATUS_ERR_PERM_DENIED;
+    ac->error_string = strdup("We do not have connection to primary router "
+                             "established, try later");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(silc_server_st_accept_client)
+{
+  SilcServerAccept ac = fsm_context;
+  SilcServer server = ac->thread->server;
+  SilcServerParamClient conn = ac->cconfig;
+  SilcServerParamConnParams param = &server->params->param;
+  SilcClientEntry client;
+  SilcClientID client_id;
+  SilcBool timedout;
+  char *username = NULL, *realname = NULL;
+  SilcUInt16 username_len;
+  SilcUInt32 id_len, mode = 0;
+  char n[128], u[384], h[256];
+  int ret;
+
+  /* Wait here for the NEW_CLIENT or RESUME_CLIENT packet */
+  SILC_FSM_SEMA_TIMEDWAIT(&ac->wait_register, 20, 0, &timedout);
+
+  if (!ac->register_packet || timedout) {
+    /** Client did not register */
+    SILC_LOG_INFO(("Client connection %s (%s) did not register",
+                  ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_NOT_REGISTERED;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  SILC_LOG_DEBUG(("Connection %s (%s) is client", ac->hostname, ac->ip));
+  SILC_LOG_INFO(("Connection %s (%s) is client", ac->hostname, ac->ip));
+
+  /* Handle resuming separately */
+  if (ac->register_packet->type == SILC_PACKET_RESUME_CLIENT) {
+    /** Resume client connection */
+    silc_fsm_next(fsm, silc_server_st_accept_resume_client);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Get connection parameters */
+  if (conn->param) {
+    param = conn->param;
+
+    if (!param->keepalive_secs)
+      param->keepalive_secs = server->params->param.keepalive_secs;
+
+    if (!param->qos && server->params->param.qos) {
+      param->qos = server->params->param.qos;
+      param->qos_rate_limit = server->params->param.qos_rate_limit;
+      param->qos_bytes_limit = server->params->param.qos_bytes_limit;
+      param->qos_limit_sec = server->params->param.qos_limit_sec;
+      param->qos_limit_usec = server->params->param.qos_limit_usec;
+    }
+
+    /* Check if to be anonymous connection */
+    if (param->anonymous)
+      mode |= SILC_UMODE_ANONYMOUS;
+  }
+
+  /* Parse NEW_CLIENT packet */
+  ret = silc_buffer_unformat(&ac->register_packet->buffer,
+                            SILC_STR_UI16_NSTRING(&username,
+                                                  &username_len),
+                            SILC_STR_UI16_STRING(&realname),
+                            SILC_STR_END);
+  if (ret < 0) {
+    /** Bad NEW_CLIENT packet */
+    SILC_LOG_ERROR(("Client %s (%s) sent incomplete information",
+                   ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_INCOMPLETE_INFORMATION;
+    ac->error_string = strdup("Bad NEW_CLIENT packet");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (!username) {
+    /** Client did not send username */
+    SILC_LOG_ERROR(("Client %s (%s) did not send its username",
+                   ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_INCOMPLETE_INFORMATION;
+    ac->error_string = strdup("You did not send username");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (username_len > 128) {
+    username_len = 128;
+    username[username_len - 1] = '\0';
+  }
+
+  memset(n, 0, sizeof(n));
+  memset(u, 0, sizeof(u));
+  memset(h, 0, sizeof(h));
+
+  ret = silc_parse_userfqdn(username, u, 128, h, sizeof(h));
+  if (ret < 2) {
+    /* Hostname not present, add it */
+    snprintf(n, sizeof(n), "%s", u);
+    snprintf(u, sizeof(u) - 1, "%s@%s", n, ac->hostname);
+  } else {
+    /* Verify that hostname is same than resolved hostname */
+    if (strcmp(ac->hostname, h)) {
+      /** Wrong hostname string */
+      SILC_LOG_ERROR(("Client %s (%s) sent wrong hostname string",
+                     ac->hostname, ac->ip));
+      ac->error = SILC_STATUS_ERR_INCOMPLETE_INFORMATION;
+      ac->error_string = strdup("You sent wrong hostname string");
+      silc_fsm_next(fsm, silc_server_st_accept_error);
+      return SILC_FSM_CONTINUE;
+    }
+    snprintf(n, sizeof(n), "%s", u);
+    snprintf(u, sizeof(u) - 1, "%s@%s", n, h);
+  }
+
+  /* If configured as anonymous, scramble the username and hostname */
+  if (mode & SILC_UMODE_ANONYMOUS) {
+    char *scramble;
+
+    u[0] = silc_rng_get_byte_fast(server->rng);
+    u[1] = silc_rng_get_byte_fast(server->rng);
+    u[2] = silc_rng_get_byte_fast(server->rng);
+    u[3] = silc_rng_get_byte_fast(server->rng);
+
+    scramble = silc_hash_babbleprint(server->sha1hash, u, strlen(u));
+    if (!scramble) {
+      /** Out of memory */
+      ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+      silc_fsm_next(fsm, silc_server_st_accept_error);
+      return SILC_FSM_CONTINUE;
+    }
+
+    username_len = strlen(scramble);
+    memset(u, 0, username_len);
+    memcpy(u, scramble, username_len);
+    u[5] = '@';
+    u[11] = '.';
+    memcpy(&u[16], ".silc", 5);
+    u[21] = '\0';
+
+    /* Get nickname from scrambled username */
+    silc_parse_userfqdn(u, n, sizeof(n), NULL, 0);
+    silc_free(scramble);
+  }
+
+  /* Create Client ID */
+  if (!silc_server_create_client_id(server, n, &client_id)) {
+    /** Could not create Client ID */
+    SILC_LOG_ERROR(("Client %s (%s) sent bad nickname string",
+                   ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_BAD_NICKNAME;
+    ac->error_string = strdup("Bad nickname");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Create client entry */
+  client = silc_server_add_client(server, n, u, realname, &client_id,
+                                 mode, ac->packet_stream);
+  if (!client) {
+    /** Could not create client entry */
+    SILC_LOG_ERROR(("Could not create new client entry"));
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Save entry data */
+  client->data = ac->data;
+  client->data.registered = TRUE;
+  client->data.local = TRUE;
+  silc_packet_set_context(ac->packet_stream, client);
+
+  /* Set destination ID to packet stream */
+  if (!silc_packet_set_ids(client->stream, 0, NULL, SILC_ID_CLIENT,
+                          &client->id)) {
+    /** Out of memory */
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Send the new client ID to the client. */
+  silc_server_send_new_id(ac->packet_stream, FALSE, &client->id,
+                         SILC_ID_CLIENT);
+
+  /* Send nice welcome to the client */
+  silc_server_send_welcome(ac, client);
+
+  /* Notify our router about new client on the SILC network */
+  silc_server_send_new_id(SILC_PRIMARY_ROUTE(server), SILC_BROADCAST(server),
+                         &client->id, SILC_ID_CLIENT);
+
+#if 0
+  /* Distribute to backup routers */
+  if (server->server_type == SILC_ROUTER) {
+    SilcBuffer idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
+                           idp->data, idp->len, FALSE, TRUE);
+    silc_buffer_free(idp);
+  }
+#endif /* 0 */
+
+  /* Check if anyone is watching this nickname */
+  if (server->server_type == SILC_ROUTER)
+    silc_server_check_watcher_list(server, client, NULL, 0);
+
+  /* Statistics */
+  /* XXX */
+
+  silc_packet_free(ac->register_packet);
+
+  /** Connection accepted */
+  silc_fsm_next(fsm, silc_server_st_accept_finish);
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(silc_server_st_accept_resume_client)
+{
+
+  /** Connection accepted */
+  silc_fsm_next(fsm, silc_server_st_accept_finish);
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(silc_server_st_accept_server)
+{
+  SilcServerAccept ac = fsm_context;
+  SilcServer server = ac->thread->server;
+  SilcBool initiator = FALSE;
+  SilcBool backup_local = FALSE;
+  SilcBool backup_router = FALSE;
+  char *backup_replace_ip = NULL;
+  SilcUInt16 backup_replace_port = 0;
+  SilcServerParamServer sconn = ac->sconfig;
+  SilcServerParamRouter rconn = ac->rconfig;
+  SilcServerEntry server_entry;
+  SilcServerID server_id;
+  SilcBool timedout;
+  unsigned char *server_name, *server_namec, *id_string;
+  SilcUInt16 id_len, name_len;
+  int ret;
+
+#if 0
+
+  /* Wait here for the NEW_SERVER packet */
+  SILC_FSM_SEMA_TIMEDWAIT(&ac->wait_register, 20, 0, &timedout);
+
+  if (!ac->register_packet || timedout) {
+    /** Server did not register */
+    SILC_LOG_INFO(("%s connection %s (%s) did not register",
+                  SILC_CONNTYPE_STRING(ac->data.type),
+                  ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_NOT_REGISTERED;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Get connection parameters */
+  if (ac->data.type == SILC_CONN_ROUTER) {
+    if (rconn) {
+      if (rconn->param) {
+       param = rconn->param;
+
+       if (!param->keepalive_secs)
+         param->keepalive_secs = server->params->param.keepalive_secs;
+
+       if (!param->qos && server->params->param.qos) {
+         param->qos = server->params->param.qos;
+         param->qos_rate_limit = server->params->param.qos_rate_limit;
+         param->qos_bytes_limit = server->params->param.qos_bytes_limit;
+         param->qos_limit_sec = server->params->param.qos_limit_sec;
+         param->qos_limit_usec = server->params->param.qos_limit_usec;
+       }
+      }
+
+      initiator = rconn->initiator;
+      backup_local = rconn->backup_local;
+      backup_router = rconn->backup_router;
+      backup_replace_ip = rconn->backup_replace_ip;
+      backup_replace_port = rconn->backup_replace_port;
+    }
+  } else if (ac->data.type == SILC_CONN_SERVER) {
+    if (sconn) {
+      if (sconn->param) {
+       param = sconn->param;
+
+       if (!param->keepalive_secs)
+         param->keepalive_secs = server->params->param.keepalive_secs;
+
+       if (!param->qos && server->params->param.qos) {
+         param->qos = server->params->param.qos;
+         param->qos_rate_limit = server->params->param.qos_rate_limit;
+         param->qos_bytes_limit = server->params->param.qos_bytes_limit;
+         param->qos_limit_sec = server->params->param.qos_limit_sec;
+         param->qos_limit_usec = server->params->param.qos_limit_usec;
+       }
+      }
+
+      backup_router = sconn->backup_router;
+    }
+  }
+
+  SILC_LOG_DEBUG(("Connection %s (%s) is %s", sock->hostname,
+                 sock->ip, ac->data.type == SILC_CONN_SERVER ?
+                 "server" : (backup_router ? "backup router" : "router")));
+  SILC_LOG_INFO(("Connection %s (%s) is %s", sock->hostname,
+                sock->ip, ac->data.type == SILC_CONN_SERVER ?
+                "server" : (backup_router ? "backup router" : "router")));
+
+  /* Parse NEW_SERVER packet */
+  ret = silc_buffer_unformat(buffer,
+                            SILC_STR_UI16_NSTRING(&id_string, &id_len),
+                            SILC_STR_UI16_NSTRING(&server_name, &name_len),
+                            SILC_STR_END);
+  if (ret < 0) {
+    /** Bad NEW_SERVER packet */
+    SILC_LOG_ERROR(("%s %s (%s) sent incomplete information",
+                   SILC_CONNTYPE_STRING(ac->data.type),
+                   ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_INCOMPLETE_INFORMATION;
+    ac->error_string = strdup("Bad NEW_SERVER packet");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  if (name_len > 256) {
+    name_len = 256;
+    server_name[name_len - 1] = '\0';
+  }
+
+  /* Get server ID */
+  if (!silc_id_str2id(id_string, id_len, SILC_ID_SERVER, &server_id,
+                     sizeof(server_id))) {
+    /** Bad Server ID */
+    SILC_LOG_ERROR(("%s %s (%s) sent incomplete information",
+                   SILC_CONNTYPE_STRING(ac->data.type),
+                   ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_INCOMPLETE_INFORMATION;
+    ac->error_string = strdup("Bad Server ID");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Check for valid server ID */
+  if (!silc_server_check_server_id(ac->ip, &server_id)) {
+    /** Invalid Server ID */
+    SILC_LOG_ERROR(("%s %s (%s) sent incomplete information",
+                   SILC_CONNTYPE_STRING(ac->data.type),
+                   ac->hostname, ac->ip));
+    ac->error = SILC_STATUS_ERR_INCOMPLETE_INFORMATION;
+    ac->error_string = strdup("Your Server ID is not based on your real "
+                             "IP address.  Check your configuration.");
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Create server entry */
+  server_entry =
+    silc_server_add_server(server, server_name,
+                          (ac->data.type == SILC_CONN_SERVER ?
+                           SILC_SERVER : SILC_ROUTER), &server_id,
+                          ac->stream);
+  if (!server_entry) {
+    /** Could not create server entry */
+    SILC_LOG_ERROR(("Could not create new server entry"));
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Save entry data */
+  server_entry->data = ac->data;
+  server_entry->data.registered = TRUE;
+  server_entry->data.local = TRUE;
+  silc_packet_set_context(ac->packet_stream, server_entry);
+
+  /* Set source ID to packet stream */
+  if (!silc_packet_set_ids(server_entry->stream, 0, NULL, SILC_ID_SERVER,
+                          &server_entry->id)) {
+    /** Out of memory */
+    ac->error = SILC_STATUS_ERR_RESOURCE_LIMIT;
+    silc_fsm_next(fsm, silc_server_st_accept_error);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* If the incoming connection is router and marked as backup router
+     then add it to be one of our backups */
+  if (ac->data.type == SILC_CONN_ROUTER && backup_router) {
+    /* Change it back to SERVER type since that's what it really is. */
+    if (backup_local)
+      server->data.type = SILC_CONN_SERVER;
+    server_entry->thread->server_type = SILC_BACKUP_ROUTER;
+
+    SILC_SERVER_SEND_OPERS(server, FALSE, TRUE, SILC_NOTIFY_TYPE_NONE,
+                          ("Backup router %s is now online",
+                           ac->hostname));
+  }
+
+  /* Check whether this connection is to be our primary router connection
+     if we do not already have the primary route. */
+  if (!backup_router && server->standalone &&
+      server_entry->data.type == SILC_CONN_ROUTER) {
+    if (silc_server_config_is_primary_route(server) && !initiator)
+      break;
+
+    SILC_LOG_DEBUG(("We are not standalone server anymore"));
+    server->standalone = FALSE;
+    if (!server->id_entry->router) {
+      server->id_entry->router = id_entry;
+      server->router = id_entry;
+    }
+  }
+
+
+
+  /* Distribute the information about new server in the SILC network
+     to our router. If we are normal server we won't send anything
+     since this connection must be our router connection. */
+  if (server->server_type == SILC_ROUTER && !server->standalone &&
+      SILC_PRIMARY_ROUTE(server) != sock)
+    silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
+                           TRUE, new_server->id, SILC_ID_SERVER,
+                           silc_id_get_len(server_id, SILC_ID_SERVER));
+
+  if (server->server_type == SILC_ROUTER) {
+    /* Distribute to backup routers */
+    SilcBuffer idp = silc_id_payload_encode(new_server->id, SILC_ID_SERVER);
+    silc_server_backup_send(server, sock->user_data, SILC_PACKET_NEW_ID, 0,
+                           idp->data, idp->len, FALSE, TRUE);
+    silc_buffer_free(idp);
+  }
+
+  /* Check whether this router connection has been replaced by an
+     backup router. If it has been then we'll disable the server and will
+     ignore everything it will send until the backup router resuming
+     protocol has been completed. */
+  if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
+      silc_server_backup_replaced_get(server, server_id, NULL)) {
+    /* Send packet to the router indicating that it cannot use this
+       connection as it has been replaced by backup router. */
+    SILC_LOG_DEBUG(("Remote router has been replaced by backup router, "
+                   "disabling its connection"));
+
+    silc_server_backup_send_replaced(server, sock);
+
+    /* Mark the router disabled. The data sent earlier will go but nothing
+       after this goes to this connection. */
+    idata->status |= SILC_IDLIST_STATUS_DISABLED;
+  } else {
+    /* If it is router announce our stuff to it. */
+    if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
+       server->server_type == SILC_ROUTER) {
+      silc_server_announce_servers(server, FALSE, 0, sock);
+      silc_server_announce_clients(server, 0, sock);
+      silc_server_announce_channels(server, 0, sock);
+    }
+
+    /* Announce our information to backup router */
+    if (new_server->thread->server_type == SILC_BACKUP_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_SERVER &&
+       server->thread->server_type == SILC_ROUTER) {
+      silc_server_announce_servers(server, TRUE, 0, sock);
+      silc_server_announce_clients(server, 0, sock);
+      silc_server_announce_channels(server, 0, sock);
+    }
+
+    /* If backup router, mark it as one of ours.  This server is considered
+       to be backup router after this setting. */
+    if (new_server->thread->server_type == SILC_BACKUP_ROUTER) {
+      SilcServerParamRouter backup;
+      backup = silc_server_params_find_backup(server, sock->ip,
+                                             sock->hostname);
+      if (backup) {
+       /* Add as our backup router */
+       silc_server_backup_add(server, new_server, backup->backup_replace_ip,
+                              backup->backup_replace_port,
+                              backup->backup_local);
+      }
+    }
+
+    /* By default the servers connected to backup router are disabled
+       until backup router has become the primary */
+    if (server->thread->server_type == SILC_BACKUP_ROUTER &&
+       server_entry->data.type == SILC_CONN_SERVER)
+      server_entry->data.disabled = TRUE;
+  }
+
+  /* Statistics */
+  /* XXX */
+
+  silc_packet_free(ac->register_packet);
+#endif /* 0 */
+
+  /** Connection accepted */
+  silc_fsm_next(fsm, silc_server_st_accept_finish);
+  return SILC_FSM_CONTINUE;
+}
+
+SILC_FSM_STATE(silc_server_st_accept_finish)
+{
+  SilcServerAccept ac = fsm_context;
+  SilcServer server = ac->thread->server;
+
+  SILC_LOG_DEBUG(("New connection accepted"));
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_accept_error)
+{
+  SilcServerAccept ac = fsm_context;
+  SilcServer server = ac->thread->server;
+
+  SILC_LOG_DEBUG(("Error accepting new connection"));
+
+  /* Disconnect remote connection */
+  if (ac->packet_stream)
+    silc_server_disconnect(server, ac->packet_stream, ac->error,
+                          ac->error_string);
+  else
+    silc_stream_destroy(ac->stream);
+
+  /* Statistics */
+  server->stat.conn_failures++;
+  if (ac->connauth)
+    server->stat.auth_failures++;
+
+  return SILC_FSM_FINISH;
+}
diff --git a/lib/silcserver/server_st_accept.h b/lib/silcserver/server_st_accept.h
new file mode 100644 (file)
index 0000000..d4ce1ae
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+
+  server_st_accept.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SERVER_ST_ACCEPT_H
+#define SERVER_ST_ACCEPT_H
+
+/***************************** State functions ******************************/
+
+void silc_server_accept_connection_dest(SilcFSM fsm, void *fsm_context,
+                                       void *destructor_context);
+SILC_FSM_STATE(silc_server_st_accept_connection);
+SILC_FSM_STATE(silc_server_st_accept_set_keys);
+SILC_FSM_STATE(silc_server_st_accept_authenticated);
+SILC_FSM_STATE(silc_server_st_accept_client);
+SILC_FSM_STATE(silc_server_st_accept_resume_client);
+SILC_FSM_STATE(silc_server_st_accept_server);
+SILC_FSM_STATE(silc_server_st_accept_finish);
+SILC_FSM_STATE(silc_server_st_accept_error);
+
+#endif /* SERVER_ST_ACCEPT_H */
diff --git a/lib/silcserver/server_st_command.c b/lib/silcserver/server_st_command.c
new file mode 100644 (file)
index 0000000..36c3d9e
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+
+  server_st_command.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/************************** Types and definitions ***************************/
+
+#define SILC_SERVER_COMMAND_CHECK(min, max)                                 \
+do {                                                                        \
+  SilcUInt32 _argc;                                                         \
+                                                                            \
+  SILC_LOG_DEBUG(("Start"));                                                \
+                                                                            \
+  _argc = silc_argument_get_arg_num(args);                                  \
+  if (_argc < min) {                                                        \
+    SILC_LOG_DEBUG(("Not enough parameters in command"));                   \
+    silc_server_command_send_status_reply(cmd,                              \
+                                         silc_command_get(cmd->payload),    \
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, \
+                                         0);                                \
+    silc_server_command_free(cmd);                                          \
+    return SILC_FSM_FINISH;                                                 \
+  }                                                                         \
+  if (_argc > max) {                                                        \
+    SILC_LOG_DEBUG(("Too many parameters in command"));                             \
+    silc_server_command_send_status_reply(cmd,                              \
+                                         silc_command_get(cmd->payload),    \
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS,   \
+                                         0);                                \
+    silc_server_command_free(cmd);                                          \
+    return SILC_FSM_FINISH;                                                 \
+  }                                                                         \
+} while(0)
+
+
+/************************ Static utility functions **************************/
+
+/* Sends simple status message as command reply packet */
+
+static void
+silc_server_command_send_status_reply(SilcServerCommand cmd,
+                                     SilcCommand command,
+                                     SilcStatus status,
+                                     SilcStatus error)
+{
+  SilcBuffer buffer;
+
+  /* Statistics */
+  cmd->thread->server->stat.commands_sent++;
+
+  SILC_LOG_DEBUG(("Sending command status %d", status));
+  buffer =
+    silc_command_reply_payload_encode_va(command, status, error,
+                                        silc_command_get_ident(cmd->payload),
+                                        0);
+  silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  buffer->data, silc_buffer_len(buffer));
+  silc_buffer_free(buffer);
+}
+
+/* Sends command status reply with one extra argument. The argument
+   type must be sent as argument. */
+
+static void
+silc_server_command_send_status_data(SilcServerCommand cmd,
+                                    SilcCommand command,
+                                    SilcStatus status,
+                                    SilcStatus error,
+                                    SilcUInt32 arg_type,
+                                    const unsigned char *arg,
+                                    SilcUInt32 arg_len)
+{
+  SilcBuffer buffer;
+
+  /* Statistics */
+  cmd->thread->server->stat.commands_sent++;
+
+  SILC_LOG_DEBUG(("Sending command status %d", status));
+
+  buffer =
+    silc_command_reply_payload_encode_va(command, status, 0,
+                                        silc_command_get_ident(cmd->payload),
+                                        1, arg_type, arg, arg_len);
+  silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  buffer->data, silc_buffer_len(buffer));
+  silc_buffer_free(buffer);
+}
+
+static void
+silc_server_command_send_status_data2(SilcServerCommand cmd,
+                                     SilcCommand command,
+                                     SilcStatus status,
+                                     SilcStatus error,
+                                     SilcUInt32 arg_type1,
+                                     const unsigned char *arg1,
+                                     SilcUInt32 arg_len1,
+                                     SilcUInt32 arg_type2,
+                                     const unsigned char *arg2,
+                                     SilcUInt32 arg_len2)
+{
+  SilcBuffer buffer;
+
+  /* Statistics */
+  cmd->thread->server->stat.commands_sent++;
+
+  SILC_LOG_DEBUG(("Sending command status %d", status));
+
+  buffer =
+    silc_command_reply_payload_encode_va(command, status, 0,
+                                        silc_command_get_ident(cmd->payload),
+                                        2, arg_type1, arg1, arg_len1,
+                                        arg_type2, arg2, arg_len2);
+  silc_packet_send(cmd->packet->stream, SILC_PACKET_COMMAND_REPLY, 0,
+                  buffer->data, silc_buffer_len(buffer));
+  silc_buffer_free(buffer);
+}
+
+void silc_server_command_pending_free(SilcServerThread thread,
+                                     SilcServerPending pending);
+
+
+/**************************** Utility functions *****************************/
+
+/* Gets command context from freelist or allocates a new one. */
+
+SilcServerCommand silc_server_command_alloc(SilcServerThread thread)
+{
+  SilcServerCommand cmd;
+
+  silc_mutex_lock(thread->server->lock);
+
+  /* Get command context from freelist or allocate new one. */
+  cmd = silc_list_get(thread->server->command_pool);
+  if (!cmd) {
+    silc_mutex_unlock(thread->server->lock);
+
+    cmd = silc_calloc(1, sizeof(*cmd));
+    if (!cmd)
+      return NULL;
+
+    SILC_LOG_DEBUG(("Allocating command context %p", cmd));
+
+    cmd->thread = thread;
+
+    return cmd;
+  }
+
+  SILC_LOG_DEBUG(("Get command context %p", cmd));
+
+  /* Delete from freelist */
+  silc_list_del(thread->server->command_pool, cmd);
+
+  cmd->thread = thread;
+
+  silc_mutex_unlock(thread->server->lock);
+
+  return cmd;
+}
+
+/* Puts the command context back to freelist */
+
+void silc_server_command_free(SilcServerCommand cmd)
+{
+  SilcServerThread thread = cmd->thread;
+
+  silc_mutex_lock(thread->server->lock);
+
+  /* Check for double free */
+#if defined(SILC_DEBUG)
+  assert(cmd->packet != NULL);
+#endif /* SILC_DEBUG */
+
+  if (cmd->packet)
+    silc_packet_free(cmd->packet);
+  cmd->packet = NULL;
+
+  if (cmd->pending)
+    silc_server_command_pending_free(thread, cmd->pending);
+
+  /* Put the packet back to freelist */
+  silc_list_add(thread->server->command_pool, cmd);
+
+  silc_mutex_unlock(thread->server->lock);
+}
+
+/* Returns pending context used to wait for a command reply. */
+
+SilcServerPending silc_server_command_pending(SilcServerThread thread,
+                                             SilcUInt16 cmd_ident)
+{
+  SilcServerPending pending;
+
+  silc_mutex_lock(thread->server->lock);
+
+  /* Check if pending already */
+  if (silc_hash_table_find(thread->server->pending_commands,
+                          SILC_32_TO_PTR(cmd_ident), NULL,
+                          (void **)&pending)) {
+    pending->refcnt++;
+    silc_mutex_unlock(thread->server->lock);
+    return pending;
+  }
+
+  pending = silc_calloc(1, sizeof(*pending));
+  if (!pending) {
+    silc_mutex_unlock(thread->server->lock);
+    return NULL;
+  }
+
+  silc_fsm_sema_init(&pending->wait_reply, &thread->fsm, 0);
+  pending->refcnt = 1;
+  pending->cmd_ident = cmd_ident;
+
+  /* Add to pending commands hash table */
+  if (!silc_hash_table_add(thread->server->pending_commands,
+                          SILC_32_TO_PTR(cmd_ident), pending)) {
+    silc_mutex_unlock(thread->server->lock);
+    silc_free(pending);
+    return NULL;
+  }
+
+  silc_mutex_unlock(thread->server->lock);
+
+  return pending;
+}
+
+/* Free's the pending command context */
+
+void silc_server_command_pending_free(SilcServerThread thread,
+                                     SilcServerPending pending)
+{
+  silc_mutex_lock(thread->server->lock);
+
+  pending->refcnt--;
+  if (pending->refcnt > 0) {
+    silc_mutex_unlock(thread->server->lock);
+    return;
+  }
+
+  /* If command reply context set, free it also */
+  if (pending->reply) {
+    pending->reply->pending = NULL;
+    silc_server_command_free(pending->reply);
+  }
+
+  /* Remove from pending commands */
+  silc_hash_table_del_by_context(thread->server->pending_commands,
+                                SILC_32_TO_PTR(pending->cmd_ident), pending);
+  silc_free(pending);
+
+  silc_mutex_unlock(thread->server->lock);
+}
+
+/* Returns pending command context for command identifier */
+
+SilcServerPending silc_server_command_pending_get(SilcServerThread thread,
+                                                 SilcUInt16 cmd_ident)
+{
+  SilcServerPending pending = NULL;
+
+  silc_mutex_lock(thread->server->lock);
+  silc_hash_table_find(thread->server->pending_commands,
+                      SILC_32_TO_PTR(cmd_ident), NULL, (void **)&pending);
+  silc_mutex_unlock(thread->server->lock);
+
+  return pending;
+}
+
+/* Signals pending command waiters.  Used by command reply routines. */
+
+void silc_server_command_pending_signal(SilcServerCommand cmd)
+{
+  SilcServerThread thread = cmd->thread;
+  SilcServerPending pending = cmd->pending;
+
+  if (!pending)
+    return;
+
+  silc_mutex_lock(thread->server->lock);
+
+  /* Signal */
+  pending->reply = cmd;
+  SILC_FSM_SEMA_POST(&pending->wait_reply);
+
+  /* Remove from pending */
+  silc_hash_table_del_by_context(thread->server->pending_commands,
+                                SILC_32_TO_PTR(pending->cmd_ident), pending);
+
+  silc_mutex_unlock(thread->server->lock);
+}
+
+
+/**************************** Command received ******************************/
+
+/* Received a COMMAND packet.  We parse the packet and process the
+   requested command. */
+
+SILC_FSM_STATE(silc_server_st_packet_command)
+{
+  SilcServerThread thread = fsm_context;
+  SilcPacket packet = state_context;
+  SilcEntryData data = silc_packet_get_context(packet->stream);
+  SilcServerCommand cmd;
+  SilcUInt32 timeout = 0;
+
+  /* Allocate command context. */
+  cmd = silc_server_command_alloc(thread);
+  if (!cmd) {
+    silc_packet_free(packet);
+    return SILC_FSM_FINISH;
+  }
+
+  cmd->packet = packet;
+
+  /* Parse the command payload in the packet */
+  cmd->payload = silc_command_payload_parse(packet->buffer.data,
+                                           silc_buffer_len(&packet->buffer));
+  if (!cmd->payload) {
+    SILC_LOG_ERROR(("Bad command payload"));
+    silc_server_command_free(cmd);
+    return SILC_FSM_FINISH;
+  }
+
+  /* If client executes commands more frequently than once in 2 seconds,
+     apply 0 - 2 seconds of timeout to prevent flooding. */
+  if (data->type == SILC_CONN_CLIENT) {
+    SilcClientEntry client = (SilcClientEntry)data;
+
+    if (client->last_command && (time(NULL) - client->last_command) < 2) {
+      client->fast_command++;
+      if (client->fast_command > 5)
+       timeout = (client->fast_command < 3 ? 0 :
+                  2 - (time(NULL) - client->last_command));
+    } else {
+      if (client->fast_command - 2 <= 0)
+       client->fast_command = 0;
+      else
+       client->fast_command -= 2;
+    }
+  }
+
+  silc_fsm_set_state_context(fsm, cmd);
+
+  SILC_LOG_DEBUG(("Processing %s command (%d timeout)",
+                 silc_get_command_name(silc_command_get(cmd->payload)),
+                 timeout));
+
+  /* Process command */
+  switch (silc_command_get(cmd->payload)) {
+
+  case SILC_COMMAND_WHOIS:
+    /** Command WHOIS */
+    silc_fsm_next_later(fsm, silc_server_st_command_whois, timeout, 0);
+    break;
+
+  case SILC_COMMAND_WHOWAS:
+    /** Command WHOWAS */
+    silc_fsm_next_later(fsm, silc_server_st_command_whowas, timeout, 0);
+    break;
+
+  case SILC_COMMAND_IDENTIFY:
+    /** Command IDENTIFY */
+    silc_fsm_next_later(fsm, silc_server_st_command_identify, timeout, 0);
+    break;
+
+  case SILC_COMMAND_NICK:
+    /** Command NICK */
+    silc_fsm_next_later(fsm, silc_server_st_command_nick, timeout, 0);
+    break;
+
+  case SILC_COMMAND_LIST:
+    /** Command LIST */
+    silc_fsm_next_later(fsm, silc_server_st_command_list, timeout, 0);
+    break;
+
+  case SILC_COMMAND_TOPIC:
+    /** Command TOPIC */
+    silc_fsm_next_later(fsm, silc_server_st_command_topic, timeout, 0);
+    break;
+
+  case SILC_COMMAND_INVITE:
+    /** Command INVITE */
+    silc_fsm_next_later(fsm, silc_server_st_command_invite, timeout, 0);
+    break;
+
+  case SILC_COMMAND_QUIT:
+    /** Command QUIT */
+    silc_fsm_next_later(fsm, silc_server_st_command_quit, timeout, 0);
+    break;
+
+  case SILC_COMMAND_KILL:
+    /** Command KILL */
+    silc_fsm_next_later(fsm, silc_server_st_command_kill, timeout, 0);
+    break;
+
+  case SILC_COMMAND_INFO:
+    /** Command INFO */
+    silc_fsm_next_later(fsm, silc_server_st_command_info, timeout, 0);
+    break;
+
+  case SILC_COMMAND_STATS:
+    /** Command STATS */
+    silc_fsm_next_later(fsm, silc_server_st_command_stats, timeout, 0);
+    break;
+
+  case SILC_COMMAND_PING:
+    /** Command INFO */
+    silc_fsm_next_later(fsm, silc_server_st_command_ping, timeout, 0);
+    break;
+
+  case SILC_COMMAND_OPER:
+    /** Command OPER */
+    silc_fsm_next_later(fsm, silc_server_st_command_oper, timeout, 0);
+    break;
+
+  case SILC_COMMAND_JOIN:
+    /** Command JOIN */
+    silc_fsm_next_later(fsm, silc_server_st_command_join, timeout, 0);
+    break;
+
+  case SILC_COMMAND_MOTD:
+    /** Command MOTD */
+    silc_fsm_next_later(fsm, silc_server_st_command_motd, timeout, 0);
+    break;
+
+  case SILC_COMMAND_UMODE:
+    /** Command UMODE */
+    silc_fsm_next_later(fsm, silc_server_st_command_umode, timeout, 0);
+    break;
+
+  case SILC_COMMAND_CMODE:
+    /** Command CMODE */
+    silc_fsm_next_later(fsm, silc_server_st_command_cmode, timeout, 0);
+    break;
+
+  case SILC_COMMAND_CUMODE:
+    /** Command CUMODE */
+    silc_fsm_next_later(fsm, silc_server_st_command_cumode, timeout, 0);
+    break;
+
+  case SILC_COMMAND_KICK:
+    /** Command KICK */
+    silc_fsm_next_later(fsm, silc_server_st_command_kick, timeout, 0);
+    break;
+
+  case SILC_COMMAND_BAN:
+    /** Command BAN */
+    silc_fsm_next_later(fsm, silc_server_st_command_ban, timeout, 0);
+    break;
+
+  case SILC_COMMAND_DETACH:
+    /** Command DETACH */
+    silc_fsm_next_later(fsm, silc_server_st_command_detach, timeout, 0);
+    break;
+
+  case SILC_COMMAND_WATCH:
+    /** Command WATCH */
+    silc_fsm_next_later(fsm, silc_server_st_command_watch, timeout, 0);
+    break;
+
+  case SILC_COMMAND_SILCOPER:
+    /** Command SILCOPER */
+    silc_fsm_next_later(fsm, silc_server_st_command_silcoper, timeout, 0);
+    break;
+
+  case SILC_COMMAND_LEAVE:
+    /** Command LEAVE */
+    silc_fsm_next_later(fsm, silc_server_st_command_leave, timeout, 0);
+    break;
+
+  case SILC_COMMAND_USERS:
+    /** Command USERS */
+    silc_fsm_next_later(fsm, silc_server_st_command_users, timeout, 0);
+    break;
+
+  case SILC_COMMAND_GETKEY:
+    /** Command GETKEY */
+    silc_fsm_next_later(fsm, silc_server_st_command_getkey, timeout, 0);
+    break;
+
+  case SILC_COMMAND_SERVICE:
+    /** Command SERVICE */
+    silc_fsm_next_later(fsm, silc_server_st_command_service, timeout, 0);
+    break;
+
+  default:
+    SILC_LOG_DEBUG(("Unknown command %d", silc_command_get(cmd->payload)));
+    silc_server_command_free(cmd);
+    return SILC_FSM_FINISH;
+    break;
+  }
+
+  /* Statistics */
+  thread->server->stat.commands_received++;
+
+  return timeout ? SILC_FSM_WAIT : SILC_FSM_CONTINUE;
+}
+
+
+/********************************** NICK ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_nick)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** LIST ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_list)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** TOPIC ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_topic)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************* INVITE ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_invite)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** QUIT ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_quit)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** KILL ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_kill)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** INFO ************************************/
+
+/* Server side of command INFO. This sends information about us to
+   the client.  If client requested specific server we will send the
+   command to that server. */
+
+SILC_FSM_STATE(silc_server_st_command_info)
+{
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** STATS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_stats)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** PING ************************************/
+
+/* Server side of command PING. */
+
+SILC_FSM_STATE(silc_server_st_command_ping)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+  SilcUInt32 tmp_len;
+  unsigned char *tmp;
+  SilcServerID server_id;
+
+  SILC_SERVER_COMMAND_CHECK(1, 1);
+
+  /* Get Server ID */
+  tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, silc_command_get(cmd->payload),
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                         0);
+    goto out;
+  }
+  if (!silc_id_payload_parse_id(tmp, tmp_len, NULL, &server_id,
+                               sizeof(server_id))) {
+    silc_server_command_send_status_data(cmd, silc_command_get(cmd->payload),
+                                        SILC_STATUS_ERR_BAD_SERVER_ID, 0,
+                                        2, tmp, tmp_len);
+    goto out;
+  }
+
+  if (SILC_ID_SERVER_COMPARE(&server_id, &thread->server->id)) {
+    /* Send our reply */
+    silc_server_command_send_status_reply(cmd, silc_command_get(cmd->payload),
+                                         SILC_STATUS_OK, 0);
+  } else {
+    silc_server_command_send_status_data(cmd, silc_command_get(cmd->payload),
+                                        SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
+                                        2, tmp, tmp_len);
+  }
+
+ out:
+  silc_server_command_free(cmd);
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** OPER ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_oper)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** JOIN ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_join)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** MOTD ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_motd)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** UMODE **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_umode)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** CMODE **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_cmode)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** CUMODE **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_cumode)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** KICK ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_kick)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/*********************************** BAN ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_ban)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** DETACH **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_detach)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** WATCH ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_watch)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************* SILCOPER *********************************/
+
+SILC_FSM_STATE(silc_server_st_command_silcoper)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** LEAVE ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_leave)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** USERS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_users)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** GETKEY **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_getkey)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** SERVICE *********************************/
+
+SILC_FSM_STATE(silc_server_st_command_service)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+
+  return SILC_FSM_FINISH;
+}
diff --git a/lib/silcserver/server_st_command.h b/lib/silcserver/server_st_command.h
new file mode 100644 (file)
index 0000000..89201f7
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+
+  server_st_command.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SERVER_ST_COMMAND_H
+#define SERVER_ST_COMMAND_H
+
+/***************************** State functions ******************************/
+
+SILC_FSM_STATE(silc_server_st_packet_command);
+SILC_FSM_STATE(silc_server_st_command_nick);
+SILC_FSM_STATE(silc_server_st_command_list);
+SILC_FSM_STATE(silc_server_st_command_topic);
+SILC_FSM_STATE(silc_server_st_command_invite);
+SILC_FSM_STATE(silc_server_st_command_quit);
+SILC_FSM_STATE(silc_server_st_command_kill);
+SILC_FSM_STATE(silc_server_st_command_info);
+SILC_FSM_STATE(silc_server_st_command_stats);
+SILC_FSM_STATE(silc_server_st_command_ping);
+SILC_FSM_STATE(silc_server_st_command_oper);
+SILC_FSM_STATE(silc_server_st_command_join);
+SILC_FSM_STATE(silc_server_st_command_motd);
+SILC_FSM_STATE(silc_server_st_command_umode);
+SILC_FSM_STATE(silc_server_st_command_cmode);
+SILC_FSM_STATE(silc_server_st_command_cumode);
+SILC_FSM_STATE(silc_server_st_command_kick);
+SILC_FSM_STATE(silc_server_st_command_ban);
+SILC_FSM_STATE(silc_server_st_command_detach);
+SILC_FSM_STATE(silc_server_st_command_watch);
+SILC_FSM_STATE(silc_server_st_command_silcoper);
+SILC_FSM_STATE(silc_server_st_command_leave);
+SILC_FSM_STATE(silc_server_st_command_users);
+SILC_FSM_STATE(silc_server_st_command_getkey);
+SILC_FSM_STATE(silc_server_st_command_service);
+
+#endif /* SERVER_ST_COMMAND_H */
diff --git a/lib/silcserver/server_st_command_reply.c b/lib/silcserver/server_st_command_reply.c
new file mode 100644 (file)
index 0000000..5fd7c34
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+
+  server_st_command_reply.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/************************** Types and definitions ***************************/
+
+/* All functions that call the COMMAND_CHECK_STATUS macros must have
+   out: and err: goto labels. */
+
+#define COMMAND_CHECK_STATUS                                           \
+do {                                                                   \
+  SILC_LOG_DEBUG(("Start"));                                           \
+  if (!silc_command_get_status(cmd->payload, &status, &error)) {       \
+    if (SILC_STATUS_IS_ERROR(status))                                  \
+      goto out;                                                                \
+    if (status == SILC_STATUS_LIST_END)                                        \
+      goto out;                                                                \
+    goto err;                                                          \
+  }                                                                    \
+} while(0)
+
+
+/************************ Static utility functions **************************/
+
+/* Free's command reply context */
+
+static void silc_server_command_reply_free(SilcServerCommand cmd)
+{
+  /* If pending commmands existed, they will eventually free this context */
+  if (!cmd->pending)
+    silc_server_command_free(cmd);
+}
+
+
+/************************* Command reply received ***************************/
+
+/* Received a COMMAND_REPLY packet.  We parse the packet and process the
+   command reply. */
+
+SILC_FSM_STATE(silc_server_st_packet_command_reply)
+{
+  SilcServerThread thread = fsm_context;
+  SilcPacket packet = state_context;
+  SilcEntryData data = silc_packet_get_context(packet->stream);
+  SilcServerCommand cmd;
+  SilcCommandPayload payload;
+  SilcCommand command;
+
+  SILC_LOG_DEBUG(("Process command reply"));
+
+  /* Allocate command context. */
+  cmd = silc_server_command_alloc(thread);
+  if (!cmd) {
+    silc_packet_free(packet);
+    return SILC_FSM_FINISH;
+  }
+
+  cmd->packet = packet;
+
+  /* Get command reply payload from packet */
+  cmd->payload = silc_command_payload_parse(packet->buffer.data,
+                                           silc_buffer_len(&packet->buffer));
+  if (!cmd->payload) {
+    SILC_LOG_DEBUG(("Bad command reply payload"));
+    silc_server_command_reply_free(cmd);
+    return SILC_FSM_FINISH;
+  }
+
+  /* Client is allowed to send reply only to WHOIS command. */
+  if (data->type == SILC_CONN_CLIENT &&
+      silc_command_get(cmd->payload) != SILC_COMMAND_WHOIS) {
+    silc_server_command_reply_free(cmd);
+    return SILC_FSM_FINISH;
+  }
+
+  /* Get all command pending for this reply */
+  cmd->pending =
+    silc_server_command_pending_get(thread,
+                                   silc_command_get_ident(cmd->payload));
+
+  silc_fsm_set_state_context(fsm, cmd);
+
+  /* Process command reply */
+  switch (silc_command_get(cmd->payload)) {
+
+  case SILC_COMMAND_WHOIS:
+    /** Command reply WHOIS */
+    silc_fsm_next(fsm, silc_server_st_command_reply_whois);
+    break;
+
+  case SILC_COMMAND_WHOWAS:
+    /** Command reply WHOWAS */
+    silc_fsm_next(fsm, silc_server_st_command_reply_whowas);
+    break;
+
+  case SILC_COMMAND_IDENTIFY:
+    /** Command reply IDENTIFY */
+    silc_fsm_next(fsm, silc_server_st_command_reply_identify);
+    break;
+
+  case SILC_COMMAND_LIST:
+    /** Command reply LIST */
+    silc_fsm_next(fsm, silc_server_st_command_reply_list);
+    break;
+
+  case SILC_COMMAND_INFO:
+    /** Command reply INFO */
+    silc_fsm_next(fsm, silc_server_st_command_reply_info);
+    break;
+
+  case SILC_COMMAND_STATS:
+    /** Command reply STATS */
+    silc_fsm_next(fsm, silc_server_st_command_reply_stats);
+    break;
+
+  case SILC_COMMAND_PING:
+    /** Command reply PING */
+    silc_fsm_next(fsm, silc_server_st_command_reply_ping);
+    break;
+
+  case SILC_COMMAND_JOIN:
+    /** Command reply JOIN */
+    silc_fsm_next(fsm, silc_server_st_command_reply_join);
+    break;
+
+  case SILC_COMMAND_MOTD:
+    /** Command reply MOTD */
+    silc_fsm_next(fsm, silc_server_st_command_reply_motd);
+    break;
+
+  case SILC_COMMAND_WATCH:
+    /** Command reply WATCH */
+    silc_fsm_next(fsm, silc_server_st_command_reply_watch);
+    break;
+
+  case SILC_COMMAND_USERS:
+    /** Command reply USERS */
+    silc_fsm_next(fsm, silc_server_st_command_reply_users);
+    break;
+
+  case SILC_COMMAND_GETKEY:
+    /** Command reply SERVICE */
+    silc_fsm_next(fsm, silc_server_st_command_reply_getkey);
+    break;
+
+  case SILC_COMMAND_SERVICE:
+    /** Command reply SERVICE */
+    silc_fsm_next(fsm, silc_server_st_command_reply_service);
+    break;
+
+  default:
+    SILC_LOG_DEBUG(("Unknown command %d", silc_command_get(cmd->payload)));
+    cmd->pending = NULL;
+    silc_server_command_reply_free(cmd);
+    return SILC_FSM_FINISH;
+    break;
+  }
+
+  /* Statistics */
+
+  return SILC_FSM_CONTINUE;
+}
+
+
+/********************************* WHOIS ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_whois)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************* WHOWAS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_whowas)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/******************************** IDENTIFY **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_identify)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** LIST ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_list)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** INFO ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_info)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** STATS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_stats)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServer server = thread->server;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+  SilcStatus status, error;
+  unsigned char *tmp;
+  SilcUInt32 tmp_len;
+  SilcBufferStruct buf;
+
+  COMMAND_CHECK_STATUS;
+
+  /* Get statistics structure */
+  tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+  if (server->server_type != SILC_ROUTER && tmp) {
+    silc_buffer_set(&buf, tmp, tmp_len);
+    silc_buffer_unformat(&buf,
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(NULL),
+                        SILC_STR_UI_INT(&server->stat.cell_clients),
+                        SILC_STR_UI_INT(&server->stat.cell_channels),
+                        SILC_STR_UI_INT(&server->stat.cell_servers),
+                        SILC_STR_UI_INT(&server->stat.clients),
+                        SILC_STR_UI_INT(&server->stat.channels),
+                        SILC_STR_UI_INT(&server->stat.servers),
+                        SILC_STR_UI_INT(&server->stat.routers),
+                        SILC_STR_UI_INT(&server->stat.server_ops),
+                        SILC_STR_UI_INT(&server->stat.router_ops),
+                        SILC_STR_END);
+  }
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** PING ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_ping)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** JOIN ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_join)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** MOTD ************************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_motd)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** WATCH ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_watch)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** USERS ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_users)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/********************************** GETKEY **********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_getkey)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServer server = thread->server;
+  SilcServerCommand cmd = state_context;
+  SilcArgumentPayload args = silc_command_get_args(cmd->payload);
+  SilcStatus status, error;
+  unsigned char *tmp;
+  SilcUInt32 len;
+  SilcClientEntry client = NULL;
+  SilcServerEntry server_entry = NULL;
+  SilcIDPayload idp = NULL;
+  SilcClientID client_id;
+  SilcServerID server_id;
+  SilcIdType id_type;
+  SilcPublicKey public_key = NULL;
+
+  COMMAND_CHECK_STATUS;
+
+  /* Get ID */
+  tmp = silc_argument_get_arg_type(args, 2, &len);
+  if (!tmp)
+    goto out;
+  idp = silc_id_payload_parse(tmp, len);
+  if (!idp)
+    goto out;
+
+  /* Get the public key payload */
+  tmp = silc_argument_get_arg_type(args, 3, &len);
+  if (!tmp)
+    goto out;
+  if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
+    goto out;
+
+  /* Store the public key */
+  id_type = silc_id_payload_get_type(idp);
+  if (id_type == SILC_ID_CLIENT) {
+    if (!silc_id_payload_get_id(idp, &client_id, sizeof(client_id)))
+      goto out;
+
+    client = silc_server_find_client_by_id(server, &client_id, TRUE, NULL);
+    if (!client)
+      goto out;
+
+    if (!client->data.public_key) {
+      silc_skr_add_public_key_simple(server->repository, public_key,
+                                    SILC_SKR_USAGE_IDENTIFICATION, client);
+      client->data.public_key = public_key;
+      public_key = NULL;
+    }
+
+  } else if (id_type == SILC_ID_SERVER) {
+    if (!silc_id_payload_get_id(idp, &server_id, sizeof(server_id)))
+      goto out;
+
+    server_entry = silc_server_find_server_by_id(server, &server_id,
+                                                TRUE, NULL);
+    if (!server_entry)
+      goto out;
+
+    server_entry->data.public_key = public_key;
+    public_key = NULL;
+  }
+
+ out:
+  silc_server_command_pending_signal(cmd);
+  if (idp)
+    silc_id_payload_free(idp);
+  if (public_key)
+    silc_pkcs_public_key_free(public_key);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
+
+
+/******************************** SERVICE ***********************************/
+
+SILC_FSM_STATE(silc_server_st_command_reply_service)
+{
+  SilcServerThread thread = fsm_context;
+  SilcServerCommand cmd = state_context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  silc_server_command_pending_signal(cmd);
+ err:
+  silc_server_command_reply_free(cmd);
+
+  return SILC_FSM_FINISH;
+}
diff --git a/lib/silcserver/server_st_command_reply.h b/lib/silcserver/server_st_command_reply.h
new file mode 100644 (file)
index 0000000..e4de13c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+
+  server_st_command_reply.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SERVER_ST_COMMAND_REPLY_H
+#define SERVER_ST_COMMAND_REPLY_H
+
+/***************************** State functions ******************************/
+
+SILC_FSM_STATE(silc_server_st_packet_command_reply);
+SILC_FSM_STATE(silc_server_st_command_reply_whois);
+SILC_FSM_STATE(silc_server_st_command_reply_whowas);
+SILC_FSM_STATE(silc_server_st_command_reply_identify);
+SILC_FSM_STATE(silc_server_st_command_reply_list);
+SILC_FSM_STATE(silc_server_st_command_reply_info);
+SILC_FSM_STATE(silc_server_st_command_reply_stats);
+SILC_FSM_STATE(silc_server_st_command_reply_ping);
+SILC_FSM_STATE(silc_server_st_command_reply_join);
+SILC_FSM_STATE(silc_server_st_command_reply_motd);
+SILC_FSM_STATE(silc_server_st_command_reply_watch);
+SILC_FSM_STATE(silc_server_st_command_reply_users);
+SILC_FSM_STATE(silc_server_st_command_reply_getkey);
+SILC_FSM_STATE(silc_server_st_command_reply_service);
+
+#endif /* SERVER_ST_COMMAND_REPLY_H */
diff --git a/lib/silcserver/server_st_connect.c b/lib/silcserver/server_st_connect.c
new file mode 100644 (file)
index 0000000..aeca059
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+
+  server_st_connect.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/* Creates connection to configured router(s) */
+
+SILC_FSM_STATE(silc_server_st_connect_router)
+{
+  SilcServer server = fsm_context;
+
+  SILC_LOG_DEBUG(("Connecting to router(s)"));
+
+  /** Wait events */
+  server->connect_router = FALSE;
+  silc_fsm_next(fsm, silc_server_st_run);
+  return SILC_FSM_CONTINUE;
+}
diff --git a/lib/silcserver/server_st_connect.h b/lib/silcserver/server_st_connect.h
new file mode 100644 (file)
index 0000000..cadc6d5
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+
+  server_st_connect.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SERVER_ST_CONNECT_H
+#define SERVER_ST_CONNECT_H
+
+SILC_FSM_STATE(silc_server_st_connect_router);
+
+#endif /* SERVER_ST_CONNECT_H */
diff --git a/lib/silcserver/server_st_notify.c b/lib/silcserver/server_st_notify.c
new file mode 100644 (file)
index 0000000..73c7aea
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+
+  server_st_notify.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+SILC_FSM_STATE(silc_server_st_packet_notify)
+{
+  SilcServerThread thread = fsm_context;
+  SilcPacket packet = state_context;
+  SilcEntryData data = silc_packet_get_context(packet->stream);
+
+  return SILC_FSM_FINISH;
+}
diff --git a/lib/silcserver/server_st_notify.h b/lib/silcserver/server_st_notify.h
new file mode 100644 (file)
index 0000000..0f4b1f3
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+
+  server_st_notify.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SERVER_ST_NOTIFY_H
+#define SERVER_ST_NOTIFY_H
+
+SILC_FSM_STATE(silc_server_st_packet_notify);
+
+#endif /* SERVER_ST_NOTIFY_H */
diff --git a/lib/silcserver/server_st_packet.c b/lib/silcserver/server_st_packet.c
new file mode 100644 (file)
index 0000000..dc1e6d5
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+
+  server_st_packet.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+/************************** Types and definitions ***************************/
+
+
+/************************ Static utility functions **************************/
+
+
+/***************************** Packet received ******************************/
+
+SILC_FSM_STATE(silc_server_st_packet_disconnect)
+{
+  SilcPacket packet = fsm_context;
+  SilcEntryData data = silc_packet_get_context(packet->stream);
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_channel_message)
+{
+#if 0
+    /*
+     * Received channel message. Channel messages are special packets
+     * (although probably most common ones) thus they are handled
+     * specially.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    idata->last_receive = time(NULL);
+    silc_server_channel_message(server, sock, packet);
+#endif
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_channel_key)
+{
+#if 0
+    /*
+     * Received key for channel. As channels are created by the router
+     * the keys are as well. We will distribute the key to all of our
+     * locally connected clients on the particular channel. Router
+     * never receives this channel and thus is ignored.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_channel_key(server, sock, packet);
+#endif
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_private_message)
+{
+#if 0
+    /*
+     * Received private message packet. The packet is coming from either
+     * client or server.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    idata->last_receive = time(NULL);
+    silc_server_private_message(server, sock, packet);
+#endif
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_private_message_key)
+{
+#if 0
+    /*
+     * Private message key packet.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_private_message_key(server, sock, packet);
+#endif
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_new_id)
+{
+#if 0
+    /*
+     * Received New ID packet. This includes some new ID that has been
+     * created. It may be for client, server or channel. This is the way
+     * to distribute information about new registered entities in the
+     * SILC network.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      silc_server_new_id_list(server, sock, packet);
+    else
+      silc_server_new_id(server, sock, packet);
+#endif
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_new_channel)
+{
+#if 0
+    /*
+     * Received new channel packet. Information about new channel in the
+     * network are distributed using this packet.
+     */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      silc_server_new_channel_list(server, sock, packet);
+    else
+      silc_server_new_channel(server, sock, packet);
+#endif
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_key_agreement)
+{
+#if 0
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_key_agreement(server, sock, packet);
+#endif
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_ftp)
+{
+#if 0
+    /* FTP packet */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_ftp(server, sock, packet);
+#endif
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_resume_router)
+{
+#if 0
+    /* Resume router packet received. This packet is received for backup
+       router resuming protocol. */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_server_backup_resume_router(server, sock, packet);
+#endif
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_packet_received)
+{
+  SilcServerThread thread = fsm_context;
+  SilcPacket packet = state_context;
+
+  SILC_LOG_DEBUG(("Received %s packet [flags %d]",
+                 silc_get_packet_name(packet->type), packet->flags));
+
+  /* Parse the packet type */
+  switch (packet->type) {
+  case SILC_PACKET_CHANNEL_MESSAGE:
+    /** Packet CHANNEL_MESSAGE */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_channel_message);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_PRIVATE_MESSAGE:
+    /** Packet PRIVATE_MESSAGE */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_private_message);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_NOTIFY:
+    /** Packet NOTIFY */
+    silc_fsm_next(fsm, silc_server_st_packet_notify);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_COMMAND:
+    /** Packet COMMAND */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_command);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_COMMAND_REPLY:
+    /** Packet COMMAND_REPLY */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_command_reply);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_CHANNEL_KEY:
+    /** Packet CHANNEL_KEY */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_channel_key);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_NEW_ID:
+    /** Packet NEW_ID */
+    silc_fsm_next(fsm, silc_server_st_packet_new_id);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_NEW_CLIENT:
+    /** Packet NEW_CLIENT */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_new_client);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_NEW_SERVER:
+    /** Packet NEW_SERVER */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_new_server);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_NEW_CHANNEL:
+    /** Packet NEW_CHANNEL */
+    silc_fsm_next(fsm, silc_server_st_packet_new_channel);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_KEY_AGREEMENT:
+    /** Packet KEY_AGREEMENT */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_key_agreement);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_FTP:
+    /** Packet FTP */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_ftp);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_RESUME_CLIENT:
+    /** Packet RESUME_CLIENT */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_resume_client);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_RESUME_ROUTER:
+    /** Packet RESUME_ROUTER */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_resume_router);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_DISCONNECT:
+    /** Packet DISCONNECT */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_disconnect);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+    /** Packet PRIVATE_MESSAGE */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_private_message_key);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_CONNECTION_AUTH_REQUEST:
+    /** Packet CONNECTION_AUTH_REQUEST */
+    if (packet->flags & SILC_PACKET_FLAG_LIST)
+      break;
+    silc_fsm_next(fsm, silc_server_st_packet_connection_auth_request);
+    return SILC_FSM_CONTINUE;
+    break;
+
+  case SILC_PACKET_HEARTBEAT:
+  case SILC_PACKET_SUCCESS:
+  case SILC_PACKET_FAILURE:
+  case SILC_PACKET_REJECT:
+  case SILC_PACKET_KEY_EXCHANGE:
+  case SILC_PACKET_KEY_EXCHANGE_1:
+  case SILC_PACKET_KEY_EXCHANGE_2:
+  case SILC_PACKET_REKEY:
+  case SILC_PACKET_REKEY_DONE:
+  case SILC_PACKET_CONNECTION_AUTH:
+  case SILC_PACKET_CONNECTION_AUTH_REQUEST:
+    /* Not handled */
+    break;
+
+  default:
+    SILC_LOG_ERROR(("Unsupported packet type %d", packet->type));
+    break;
+  }
+
+  silc_packet_free(packet);
+  return SILC_FSM_FINISH;
+}
+
+/* Received NEW_CLIENT packet, used to register client to SILC network. */
+
+SILC_FSM_STATE(silc_server_st_packet_new_client)
+{
+  SilcServerThread thread = fsm_context;
+  SilcPacket packet = state_context;
+  SilcServerAccept ac = silc_packet_get_context(packet->stream);
+
+  if (!ac || ac->register_packet) {
+    silc_packet_free(packet);
+    return SILC_FSM_FINISH;
+  }
+
+  /* Signal that client registers to network */
+  ac->register_packet = packet;
+  SILC_FSM_SEMA_POST(&ac->wait_register);
+
+  return SILC_FSM_FINISH;
+}
+
+/* Received NEW_SERVER packet, used to register server to SILC network. */
+
+SILC_FSM_STATE(silc_server_st_packet_new_server)
+{
+  SilcServerThread thread = fsm_context;
+  SilcPacket packet = state_context;
+  SilcServerAccept ac = silc_packet_get_context(packet->stream);
+
+  if (!ac || ac->register_packet) {
+    silc_packet_free(packet);
+    return SILC_FSM_FINISH;
+  }
+
+  /* Signal that server registers to network */
+  ac->register_packet = packet;
+  SILC_FSM_SEMA_POST(&ac->wait_register);
+
+  return SILC_FSM_FINISH;
+}
+
+/* Received RESUME_CLIENT packet, used to resume detached session. */
+
+SILC_FSM_STATE(silc_server_st_packet_resume_client)
+{
+  SilcServerThread thread = fsm_context;
+  SilcPacket packet = state_context;
+  SilcServerAccept ac = silc_packet_get_context(packet->stream);
+
+  if (!ac || ac->register_packet) {
+    silc_packet_free(packet);
+    return SILC_FSM_FINISH;
+  }
+
+  /* Signal that client resumes session */
+  ac->register_packet = packet;
+  SILC_FSM_SEMA_POST(&ac->wait_register);
+
+  return SILC_FSM_FINISH;
+}
diff --git a/lib/silcserver/server_st_packet.h b/lib/silcserver/server_st_packet.h
new file mode 100644 (file)
index 0000000..79cf59b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+
+  server_st_packet.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SERVER_ST_PACKET_H
+#define SERVER_ST_PACKET_H
+
+SILC_FSM_STATE(silc_server_st_packet_received);
+SILC_FSM_STATE(silc_server_st_packet_new_client);
+SILC_FSM_STATE(silc_server_st_packet_new_server);
+SILC_FSM_STATE(silc_server_st_packet_resume_client);
+
+#endif /* SERVER_ST_PACKET_H */
diff --git a/lib/silcserver/server_st_query.c b/lib/silcserver/server_st_query.c
new file mode 100644 (file)
index 0000000..2737b90
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+
+  server_st_query.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcserver.h"
+#include "server_internal.h"
+
+SILC_FSM_STATE(silc_server_st_command_whois)
+{
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_command_whowas)
+{
+
+  return SILC_FSM_FINISH;
+}
+
+SILC_FSM_STATE(silc_server_st_command_identify)
+{
+  return SILC_FSM_FINISH;
+}
diff --git a/lib/silcserver/server_st_query.h b/lib/silcserver/server_st_query.h
new file mode 100644 (file)
index 0000000..6b1ef97
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+
+  server_st_query.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SERVER_ST_QUERY_H
+#define SERVER_ST_QUERY_H
+
+SILC_FSM_STATE(silc_server_st_command_whois);
+SILC_FSM_STATE(silc_server_st_command_whowas);
+SILC_FSM_STATE(silc_server_st_command_identify);
+
+#endif /* SERVER_ST_QUERY_H */
diff --git a/lib/silcserver/silcserver.h b/lib/silcserver/silcserver.h
new file mode 100644 (file)
index 0000000..981587b
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+
+  silcserver.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+/****h* silcserver/Server Library Interface
+ *
+ * DESCRIPTION
+ *
+ *
+ ***/
+
+#ifndef SILCSERVER_H
+#define SILCSERVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "silcserver_params.h"
+
+/****s* silcserver/SilcServerAPI/SilcServer
+ *
+ * NAME
+ *
+ *    typedef struct SilcServerStruct *SilcServer;
+ *
+ * DESCRIPTION
+ *
+ *    This context is the actual SILC Server context and is allocated
+ *    by silc_server_alloc and given as argument to all silc_server_*
+ *    functions.  It is freed by the silc_server_free function.
+ *
+ ***/
+typedef struct SilcServerStruct *SilcServer;
+
+/****f* silcserver/SilcServerAPI/SilcServerRunning
+ *
+ * SYNOPSIS
+ *
+ *    typedef void (*SilcServerRunning)(SilcServer server, SilcBool running,
+ *                                      void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Called to indicate that the server is up and running and ready to
+ *    accept new connection and create connections to remote router, if
+ *    any has been configured.
+ *
+ ***/
+typedef void (*SilcServerRunning)(SilcServer server, void *context);
+
+/****f* silcserver/SilcServerAPI/SilcServerStop
+ *
+ * SYNOPSIS
+ *
+ *    typedef void (*SilcServerStop)(SilcServer server, void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Called to indicate that the server has stopped and can be freed now.
+ *
+ ***/
+typedef void (*SilcServerStop)(SilcServer server, void *context);
+
+/****f* silcserver/SilcServerAPI/silc_server_alloc
+ *
+ * SYNOPSIS
+ *
+ *    SilcServer silc_server_alloc(void *app_context, SilcServerParams params,
+ *                                 SilcSchedule schedule);
+ *
+ * DESCRIPTION
+ *
+ *    Allocates SILC server context and returns it.  Returns NULL if case
+ *    of error.  The `app_context' is application specific context and
+ *    can be retrieved from the server by using silc_server_get_context
+ *    function.  The `params' context contains the SILC server parameters
+ *    that application has gathered most likely from a configuration file
+ *    or similar source.  The `params' and everything inside are allocated
+ *    by the caller, but the server library will own it and free it.  It
+ *    may also modify its content.
+ *
+ ***/
+SilcServer silc_server_alloc(void *app_context, SilcServerParams params,
+                            SilcSchedule schedule);
+
+/****f* silcserver/SilcServerAPI/silc_server_free
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_free(SilcServer server);
+ *
+ * DESCRIPTION
+ *
+ *    Free the server context and all allocated resources.
+ *
+ ***/
+void silc_server_free(SilcServer server);
+
+/****f* silcserver/SilcServerAPI/silc_server_run
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_run(SilcServer server, SilcServerRunning running,
+ *                         void *running_context);
+ *
+ * DESCRIPTION
+ *
+ *    Starts the SILC server.  This function returns immediately and the
+ *    SilcSchedule must be run after this functions returns or it must be
+ *    already running when this function is called.  The `running' callback
+ *    will be called once the server is up and running.
+ *
+ ***/
+void silc_server_run(SilcServer server, SilcServerRunning running,
+                    void *running_context);
+
+/****f* silcserver/SilcServerAPI/silc_server_run
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_stop(SilcServer server, SilcServerStop stop_callback,
+ *                          void *stop_context);
+ *
+ * DESCRIPTION
+ *
+ *    Stops the SILC server.  Stopping of the server is asynchronous and
+ *    once it has stopped the `stopped' callback will be called with the
+ *    `stop_context'.  Application should not exit without calling this
+ *    function.
+ *
+ ***/
+void silc_server_stop(SilcServer server, SilcServerStop stopped,
+                     void *stop_context);
+
+#include "server_internal.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILCSERVER_H */
diff --git a/lib/silcserver/silcserver_params.h b/lib/silcserver/silcserver_params.h
new file mode 100644 (file)
index 0000000..2cef5aa
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+
+  silcserver_params.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 1997 - 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SILCSERVER_PARAMS_H
+#define SILCSERVER_PARAMS_H
+
+typedef struct SilcServerParamCipherStruct {
+  char *name;
+  char *module;
+  SilcUInt32 key_length;
+  SilcUInt32 block_length;
+  struct SilcServerParamCipherStruct *next;
+} *SilcServerParamCipher;
+
+typedef struct SilcServerParamHashStruct {
+  char *name;
+  char *module;
+  SilcUInt32 block_length;
+  SilcUInt32 digest_length;
+  struct SilcServerParamHashStruct *next;
+} *SilcServerParamHash;
+
+typedef struct SilcServerParamHmacStruct {
+  char *name;
+  char *hash;
+  SilcUInt32 mac_length;
+  struct SilcServerParamHmacStruct *next;
+} *SilcServerParamHmac;
+
+typedef struct SilcServerParamPkcsStruct {
+  char *name;
+  struct SilcServerParamPkcsStruct *next;
+} *SilcServerParamPkcs;
+
+typedef struct SilcServerParamInterfaceStruct {
+  char *ip;                            /* IP address */
+  SilcUInt16 port;                     /* Port */
+  struct SilcServerParamInterfaceStruct *next;
+} *SilcServerParamInterface;
+
+typedef struct SilcServerParamServerInfoStruct {
+  char *server_name;                   /* Server name */
+  SilcList interfaces;                 /* SilcServerParamInterface */
+  char *server_type;                   /* E.g. "Test Server" */
+  char *location;                      /* Geographic location */
+  char *admin;                         /* Admin's full name */
+  char *email;                         /* Admin's email address */
+  char *user;                          /* Userid the server use */
+  char *group;                         /* Groupid the server use  */
+  char *motd_file;                     /* Path to text MOTD file */
+  char *pid_file;                      /* Path to the PID file */
+  SilcPublicKey public_key;            /* Server's public key */
+  SilcPrivateKey private_key;          /* Server's private key */
+} *SilcServerParamServerInfo;
+
+typedef struct SilcServerParamLoggingStruct {
+  char *file;
+  SilcUInt32 maxsize;
+} *SilcServerParamLogging;
+
+/* Connection parameters */
+typedef struct SilcServerParamConnParamsObject {
+  struct SilcServerParamConnParams *next;
+  char *name;
+  char *version_protocol;
+  char *version_software;
+  char *version_software_vendor;
+  SilcUInt32 connections_max;
+  SilcUInt32 connections_max_per_host;
+  SilcUInt32 keepalive_secs;
+  SilcUInt32 reconnect_count;
+  SilcUInt32 reconnect_interval;
+  SilcUInt32 reconnect_interval_max;
+  SilcUInt32 key_exchange_rekey;
+  SilcUInt32 qos_rate_limit;
+  SilcUInt32 qos_bytes_limit;
+  SilcUInt32 qos_limit_sec;
+  SilcUInt32 qos_limit_usec;
+  SilcUInt32 chlimit;
+  unsigned int key_exchange_pfs      : 1;
+  unsigned int reconnect_keep_trying : 1;
+  unsigned int anonymous             : 1;
+  unsigned int qos                   : 1;
+} *SilcServerParamConnParams, SilcServerParamConnParamsStruct;
+
+/* Holds all client authentication data from config file */
+typedef struct SilcServerParamClientStruct {
+  char *host;
+  unsigned char *passphrase;
+  SilcUInt32 passphrase_len;
+  SilcHashTable publickeys;
+  SilcBool pubkey_auth;
+  SilcServerParamConnParams param;
+  struct SilcServerParamClientStruct *next;
+} *SilcServerParamClient;
+
+/* Holds all server's administrators authentication data from config file */
+typedef struct SilcServerParamAdminStruct {
+  char *host;
+  char *user;
+  char *nick;
+  unsigned char *passphrase;
+  SilcUInt32 passphrase_len;
+  SilcHashTable publickeys;
+  struct SilcServerParamAdminStruct *next;
+} *SilcServerParamAdmin;
+
+/* Holds all configured denied connections from config file */
+typedef struct SilcServerParamDenyStruct {
+  char *host;
+  char *reason;
+  struct SilcServerParamDenyStruct *next;
+} *SilcServerParamDeny;
+
+/* Holds all configured server connections from config file */
+typedef struct SilcServerParamServerStruct {
+  char *host;
+  unsigned char *passphrase;
+  SilcUInt32 passphrase_len;
+  SilcHashTable publickeys;
+  SilcBool pubkey_auth;
+  SilcServerParamConnParams param;
+  SilcBool backup_router;
+  struct SilcServerParamServerStruct *next;
+} *SilcServerParamServer;
+
+/* Holds all configured router connections from config file */
+typedef struct SilcServerParamRouterStruct {
+  char *host;
+  unsigned char *passphrase;
+  SilcUInt32 passphrase_len;
+  SilcHashTable publickeys;
+  SilcBool pubkey_auth;
+  SilcUInt16 port;
+  SilcServerParamConnParams param;
+  SilcBool initiator;
+  SilcBool backup_router;
+  char *backup_replace_ip;
+  SilcUInt16 backup_replace_port;
+  SilcBool backup_local;
+  struct SilcServerParamRouterStruct *next;
+} *SilcServerParamRouter;
+
+typedef struct {
+  /* Server information */
+  SilcServerParamServerInfo server_info;
+
+  /* Global flags */
+  unsigned int prefer_passphrase_auth   : 1;
+  unsigned int require_reverse_lookup   : 1;
+  unsigned int detach_disabled          : 1;
+
+  /* Threads support */
+  unsigned int use_threads              : 1;
+  SilcUInt32 connections_per_thread;
+
+  /* Default connection parameters */
+  SilcServerParamConnParamsStruct param;
+
+  SilcUInt32 channel_rekey_secs;
+  SilcUInt32 key_exchange_timeout;
+  SilcUInt32 conn_auth_timeout;
+  SilcUInt32 detach_timeout;
+  SilcBool logging_timestamp;
+  SilcBool logging_quick;
+  long logging_flushdelay;
+  char *debug_string;
+
+  /* Supported ciphers, hashes, hmacs and PKCS's */
+  SilcList cipher;                    /* SilcServerParamCipher */
+  SilcList hash;                      /* SilcServerParamHash */
+  SilcList hmac;                      /* SilcServerParamHmac */
+  SilcList pkcs;                      /* SilcServerParamPkcs */
+
+  /* Configured client, server and router connections */
+  SilcList clients;                   /* SilcServerParamClient */
+  SilcList servers;                   /* SilcServerParamServer */
+  SilcList routers;                   /* SilcServerParamRouter */
+
+  /* Configured connections parameters */
+  SilcList conn_params;                       /* SilcServerParamConnParams */
+
+  /* Denied connections */
+  SilcList denied;                    /* SilcServerParamDeny */
+
+  /* Configured server administrators */
+  SilcList admins;                    /* SilcServerParamAdmin */
+
+  SilcServerParamLogging *logging_info;
+  SilcServerParamLogging *logging_warnings;
+  SilcServerParamLogging *logging_errors;
+  SilcServerParamLogging *logging_fatals;
+
+  SilcUInt8 refcnt;                   /* Reference counter */
+} *SilcServerParams;
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_alloc
+ *
+ * SYNOPSIS
+ *
+ *    SilcServerParams silc_server_params_alloc(void);
+ *
+ * DESCRIPTION
+ *
+ *    Allocates server parameters context.
+ *
+ ***/
+SilcServerParams silc_server_params_alloc(void);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_free
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_free(SilcServerParams params);
+ *
+ * DESCRIPTION
+ *
+ *    Frees server parameters and all allocated resources in it.
+ *
+ ***/
+void silc_server_params_free(SilcServerParams params);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_serverinfo_alloc
+ *
+ * SYNOPSIS
+ *
+ *    SilcServerParamServerInfo silc_server_params_serverinfo_alloc(void);
+ *
+ * DESCRIPTION
+ *
+ *    Allocates server information context.  This does not have to be freed
+ *    by the caller.  It is freed when the server parameters are freed.
+ *
+ ***/
+SilcServerParamServerInfo silc_server_params_serverinfo_alloc(void);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_serverinfo_alloc
+ *
+ * SYNOPSIS
+ *
+ *    void
+ *    silc_server_params_serverinfo_add_iface(SilcServerParamServerInfo info,
+ *                                            SilcServerParamInterface iface);
+ *
+ * DESCRIPTION
+ *
+ *    Adds interface to server information parameters.  The first added
+ *    interface is the primary interface.
+ *
+ ***/
+void silc_server_params_serverinfo_add_iface(SilcServerParamServerInfo info,
+                                            SilcServerParamInterface iface);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_set_serverinfo
+ *
+ * SYNOPSIS
+ *
+ *    void
+ *    silc_server_params_set_serverinfo(SilcServerParams params,
+ *                                      SilcServerParamServerInfo
+ *                                                       server_info);
+ *
+ * DESCRIPTION
+ *
+ *    Set server's information to server parameters.
+ *
+ ***/
+void silc_server_params_set_serverinfo(SilcServerParams params,
+                                      SilcServerParamServerInfo server_info);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_cipher
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_cipher(SilcServerParams params,
+ *                                       SilcServerParamCipher cipher);
+ *
+ * DESCRIPTION
+ *
+ *    Adds a cipher to server parameters.
+ *
+ ***/
+void silc_server_params_add_cipher(SilcServerParams params,
+                                  SilcServerParamCipher cipher);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_hash
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_hash(SilcServerParams params,
+ *                                     SilcServerParamHash hash);
+ *
+ * DESCRIPTION
+ *
+ *    Adds a hash function to server parameters.
+ *
+ ***/
+void silc_server_params_add_hash(SilcServerParams params,
+                                SilcServerParamHash hash);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_hmac
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_hmac(SilcServerParams params,
+ *                                     SilcServerParamHmac hmac);
+ *
+ * DESCRIPTION
+ *
+ *    Adds a HMAC to server parameters.
+ *
+ ***/
+void silc_server_params_add_hmac(SilcServerParams params,
+                                SilcServerParamHmac hmac);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_pkcs
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_pkcs(SilcServerParams params,
+ *                                     SilcServerParamPkcs pkcs);
+ *
+ * DESCRIPTION
+ *
+ *    Adds a HMAC to server parameters.
+ *
+ ***/
+void silc_server_params_add_pkcs(SilcServerParams params,
+                                SilcServerParamPkcs pkcs);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_client
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_client(SilcServerParams params,
+ *                                       SilcServerParamClient client);
+ *
+ * DESCRIPTION
+ *
+ *    Adds a client connection to server parameters.
+ *
+ ***/
+void silc_server_params_add_client(SilcServerParams params,
+                                  SilcServerParamClient client);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_server
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_server(SilcServerParams params,
+ *                                       SilcServerParamServer server);
+ *
+ * DESCRIPTION
+ *
+ *    Adds a server connection to server parameters.
+ *
+ ***/
+void silc_server_params_add_server(SilcServerParams params,
+                                  SilcServerParamServer server);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_router
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_router(SilcServerParams params,
+ *                                       SilcServerParamRouter router);
+ *
+ * DESCRIPTION
+ *
+ *    Adds a router connection to server parameters.
+ *
+ ***/
+void silc_server_params_add_router(SilcServerParams params,
+                                  SilcServerParamRouter router);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_connparam
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_connparam(SilcServerParams params,
+ *                                          SilcServerParamConnParams param);
+ *
+ * DESCRIPTION
+ *
+ *    Adds a connection parameters to server parameters.
+ *
+ ***/
+void silc_server_params_add_connparam(SilcServerParams params,
+                                     SilcServerParamConnParams param);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_deny
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_deny(SilcServerParams params,
+ *                                     SilcServerParamDeny deny);
+ *
+ * DESCRIPTION
+ *
+ *    Adds a denied connection to server parameters.
+ *
+ ***/
+void silc_server_params_add_deny(SilcServerParams params,
+                                SilcServerParamDeny deny);
+
+/****f* silcserver/SilcServerParamsAPI/silc_server_params_add_admin
+ *
+ * SYNOPSIS
+ *
+ *    void silc_server_params_add_admin(SilcServerParams params,
+ *                                      SilcServerParamAdmin admin);
+ *
+ * DESCRIPTION
+ *
+ *    Adds an server administrator to server parameters.
+ *
+ ***/
+void silc_server_params_add_admin(SilcServerParams params,
+                                 SilcServerParamAdmin admin);
+
+#endif /* SILCSERVER_PARAMS_H */
diff --git a/lib/silcserver/tests/Makefile.am b/lib/silcserver/tests/Makefile.am
new file mode 100644 (file)
index 0000000..074b562
--- /dev/null
@@ -0,0 +1,27 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@silcnet.org>
+#
+#  Copyright (C) 2002 Pekk5 Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; version 2 of the License.
+#
+#  This program 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 General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+bin_PROGRAMS =         test_silcserver
+
+test_silcserver_SOURCES = test_silcserver.c
+
+LIBS = $(SILC_COMMON_LIBS)
+LDADD = -L.. -L../.. -lsilc -lsilcserver
+
+include $(top_srcdir)/Makefile.defines.in
diff --git a/lib/silcserver/tests/test_silcserver.c b/lib/silcserver/tests/test_silcserver.c
new file mode 100644 (file)
index 0000000..5c27a3e
--- /dev/null
@@ -0,0 +1,102 @@
+#include "silc.h"
+#include "silcserver.h"
+
+SilcSchedule schedule;
+
+static void running(SilcServer server, void *context)
+{
+  SILC_LOG_DEBUG(("***** RUNNING"));
+}
+
+static void stopped(SilcServer server, void *context)
+{
+  SILC_LOG_DEBUG(("***** STOPPED"));
+  silc_schedule_stop(schedule);
+}
+
+int main(int argc, char **argv)
+{
+  SilcBool success = FALSE;
+  SilcServer server;
+  SilcServerParams params;
+  SilcServerParamServerInfo info;
+  SilcServerParamInterface iface;
+  SilcServerParamClient client_all;
+
+  if (argc > 1 && !strcmp(argv[1], "-d")) {
+    silc_log_debug(TRUE);
+    silc_log_debug_hexdump(TRUE);
+    silc_log_set_debug_string("*server*,*skr*,*ske*,*connauth*,*packet*,*stream*,*net*");
+  }
+
+  SILC_LOG_DEBUG(("Allocating scheduler"));
+  schedule = silc_schedule_init(0, NULL);
+
+  silc_cipher_register_default();
+  silc_pkcs_register_default();
+  silc_hash_register_default();
+  silc_hmac_register_default();
+
+  SILC_LOG_DEBUG(("Allocating server params context"));
+  params = silc_server_params_alloc();
+  if (!params)
+    goto err;
+
+  SILC_LOG_DEBUG(("Creating server params"));
+
+  info = silc_server_params_serverinfo_alloc();
+  if (!info)
+    goto err;
+  info->server_name = strdup("test server");
+
+  if (!silc_load_key_pair("test.pub", "test.prv", "", NULL,
+                         &info->public_key,
+                         &info->private_key)) {
+    if (!silc_create_key_pair("rsa", 2048, "test.pub", "test.prv", NULL, "",
+                             NULL,
+                             &info->public_key,
+                             &info->private_key, FALSE)) {
+      goto err;
+    }
+  }
+
+  iface = silc_calloc(1, sizeof(*iface));
+  if (!iface)
+    goto err;
+  iface->ip = strdup("127.0.0.1");
+  iface->port = 1334;
+  silc_server_params_serverinfo_add_iface(info, iface);
+  silc_server_params_set_serverinfo(params, info);
+
+  client_all = silc_calloc(1, sizeof(*client_all));
+  if (!client_all)
+    goto err;
+  silc_server_params_add_client(params, client_all);
+
+  params->use_threads = TRUE;
+
+  SILC_LOG_DEBUG(("Allocating server context"));
+  server = silc_server_alloc(NULL, params, schedule);
+  if (!server) {
+    SILC_LOG_DEBUG(("Error allocating server"));
+    goto err;
+  }
+
+  SILC_LOG_DEBUG(("Running server"));
+  silc_server_run(server, running, NULL);
+
+  SILC_LOG_DEBUG(("Running scheduler"));
+  silc_schedule(schedule);
+
+  silc_server_free(server);
+  silc_server_params_free(params);
+  silc_schedule_uninit(schedule);
+
+  success = TRUE;
+
+ err:
+  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
+  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+  return success;
+}
index 27d37c054f6eec382526a25de559105ff86876f2..a60437235562fe9baa86484eb4cd634a314cd6f5 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcsftp.h"
 #include "sftp_util.h"
 
index b91e212ec5639146b0bcbd7fe985317bb52dcb8b..dc0557612845f5381a79cb66eed4053095a0b417 100644 (file)
@@ -19,7 +19,7 @@
 /* $Id$ */
 /* XXX TODO Win32 support */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcsftp.h"
 #include "silcsftp_fs.h"
 #include "sftp_util.h"
index cbfbe43c2ca63ca5ddeaef931c33de5cf75f2e07..de0b52ef9d7eaade18f4a1ac0b4418af93a4d1f6 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcsftp.h"
 #include "silcsftp_fs.h"
 #include "sftp_util.h"
index dc2f5cff67e19fab735a3a158518b0e0289e298a..b3f79d5a87d978f8f69267714e46960c69d1a719 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcsftp.h"
 #include "sftp_util.h"
 
index d74a98ecd7ecf0170a7dbdffb6876e3048b0c7d2..e181403d0fba3134dced0b5b397ada47d1098020 100644 (file)
@@ -29,7 +29,7 @@
    silc_sftp_close();
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcsftp.h"
 
 typedef struct {
index 29d39d6b7a8ca4423d69fb05b6357c6a9af80d69..9510e53e24776dcd58dbcb636b62d1a475e31ce5 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcsftp.h"
 
 typedef struct {
index dcec015024b66e353671b8f86f39cae5913e41f2..7a00dafdf318cbd3f03abe42fc4afddde9342ceb 100644 (file)
@@ -40,7 +40,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* 
    SILC Module (SIM) Context.
index 1e839db33d76624ad5451c97e001b9b65ffd05c9..67cb5bf1350f640d9e21cbd176b0661c666fa536 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifdef SILC_SIM                        /* SIM support enabled */
 
index c37dd945b1cd46a62fc57ea03b4ed175701a0af5..09f517de4e7b1dde8f8c4d0fd14ee0c0988f6d81 100644 (file)
@@ -2,9 +2,6 @@
 @LIBRARY=SILC Key Exchange Library
 @FILENAME=silcskelib.html
 @LINK=silcske.html:SILC SKE Interface
-@LINK=silcske_status.html:SKE Status Types
-@LINK=silcske_groups.html:SKE Diffie Hellman Groups
-@LINK=silcske_payload.html:SKE Payloads
 -->
 
 <big><b>SILC Key Exchange Library</b></big>
@@ -21,4 +18,3 @@ It provides the key exchange protocol for all SILC applications.
 
 <br /><br />
 @LINKS@
-
index b6cad66559bf0606066546822672eeb95efb2901..0c54eb5f79959f104912f4f08c85ee19d7e156e7 100644 (file)
@@ -22,14 +22,15 @@ noinst_LTLIBRARIES = libsilcske.la
 libsilcske_la_SOURCES = \
        silcske.c \
        payload.c \
-        groups.c
+        groups.c  \
+       silcconnauth.c
 
 #ifdef SILC_DIST_TOOLKIT
 include_HEADERS =              \
        silcske_groups.h        \
        silcske_payload.h       \
-       silcske_status.h        \
-       silcske.h
+       silcske.h               \
+       silcconnauth.h
 #endif SILC_DIST_TOOLKIT
 
 EXTRA_DIST = *.h
index 2ba52de9c802d268699c8f94343f5e45781950f9..992779123a54c0f85663fa53b216738d02fd26cb 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "groups_internal.h"
 
 /* Fixed and public Diffie Hellman Groups defined by the SKE
index be670e467323713af42b9b0cfb1d73a947ca66dc..ad45ea8d74a1d14410310a722affb97e80a36506 100644 (file)
@@ -18,7 +18,8 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
+#include "silcske_i.h"
 
 /* Encodes Key Exchange Start Payload into a SILC Buffer to be sent
    to the other end. */
index cb4713708ae0305eb360d7ec167310bee3d46f41..c230e36b72ed4a7b820d58aa1296d2316c7228d2 100644 (file)
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcske.h"
 #include "groups_internal.h"
 
-/* Static functions */
-static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
-                                        SilcUInt32 len,
-                                        SilcMPInt *rnd);
-static SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
-                                       unsigned char *return_hash,
-                                       SilcUInt32 *return_hash_len,
-                                       int initiator);
-static SilcSKEStatus
-silc_ske_select_security_properties(SilcSKE ske,
-                                   const char *version,
-                                   SilcSKEStartPayload payload,
-                                   SilcSKEStartPayload remote_payload);
+/************************** Types and definitions ***************************/
+
+/* Structure to hold all SKE callbacks. */
+struct SilcSKECallbacksStruct {
+  SilcSKEVerifyCb verify_key;
+  SilcSKECompletionCb completed;
+  void *context;
+};
+
+
+/************************ Static utility functions **************************/
+
 SilcSKEKeyMaterial
 silc_ske_process_key_material_data(unsigned char *data,
                                   SilcUInt32 data_len,
@@ -47,142 +46,27 @@ silc_ske_process_key_material(SilcSKE ske,
                              SilcUInt32 req_iv_len,
                              SilcUInt32 req_enc_key_len,
                              SilcUInt32 req_hmac_key_len);
-static void silc_ske_packet_receive(SilcPacketEngine engine,
-                                   SilcPacketStream stream,
-                                   SilcPacket packet,
-                                   void *callback_context,
-                                   void *app_context);
-static void silc_ske_packet_eos(SilcPacketEngine engine,
-                               SilcPacketStream stream,
-                               void *callback_context,
-                               void *app_context);
-static void silc_ske_packet_error(SilcPacketEngine engine,
-                                 SilcPacketStream stream,
-                                 SilcPacketError error,
-                                 void *callback_context,
-                                 void *app_context);
-
-/* Structure to hold all SKE callbacks. */
-struct SilcSKECallbacksStruct {
-  SilcSKEVerifyCb verify_key;
-  SilcSKECheckVersionCb check_version;
-  SilcSKECompletionCb completed;
-  void *context;
-};
-
-/* Packet stream callbacks */
-static SilcPacketCallbacks silc_ske_stream_cbs =
-{
-  silc_ske_packet_receive,
-  silc_ske_packet_eos,
-  silc_ske_packet_error
-};
-
-/* Allocates new SKE object. */
-
-SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule, void *context)
-{
-  SilcSKE ske;
-
-  SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
-
-  if (!rng || !schedule)
-    return NULL;
-
-  ske = silc_calloc(1, sizeof(*ske));
-  if (!ske)
-    return NULL;
-  ske->status = SILC_SKE_STATUS_OK;
-  ske->rng = rng;
-  ske->user_data = context;
-  ske->schedule = schedule;
-  ske->users = 1;
-
-  return ske;
-}
-
-/* Free's SKE object. */
-
-void silc_ske_free(SilcSKE ske)
-{
-  ske->users--;
-  if (ske->users > 0) {
-    SILC_LOG_DEBUG(("Key Exchange set to FREED status"));
-    ske->status = SILC_SKE_STATUS_FREED;
-    return;
-  }
-
-  SILC_LOG_DEBUG(("Freeing Key Exchange object"));
-
-  if (ske) {
-    /* Free start payload */
-    if (ske->start_payload)
-      silc_ske_payload_start_free(ske->start_payload);
-
-    /* Free KE payload */
-    if (ske->ke1_payload)
-      silc_ske_payload_ke_free(ske->ke1_payload);
-    if (ske->ke2_payload)
-      silc_ske_payload_ke_free(ske->ke2_payload);
-    silc_free(ske->remote_version);
-
-    /* Free rest */
-    if (ske->prop) {
-      if (ske->prop->group)
-       silc_ske_group_free(ske->prop->group);
-      if (ske->prop->pkcs)
-       silc_pkcs_free(ske->prop->pkcs);
-      if (ske->prop->cipher)
-       silc_cipher_free(ske->prop->cipher);
-      if (ske->prop->hash)
-       silc_hash_free(ske->prop->hash);
-      if (ske->prop->hmac)
-       silc_hmac_free(ske->prop->hmac);
-      silc_free(ske->prop);
-    }
-    if (ske->start_payload_copy)
-      silc_buffer_free(ske->start_payload_copy);
-    if (ske->x) {
-      silc_mp_uninit(ske->x);
-      silc_free(ske->x);
-    }
-    if (ske->KEY) {
-      silc_mp_uninit(ske->KEY);
-      silc_free(ske->KEY);
-    }
-    silc_free(ske->hash);
-    silc_free(ske->callbacks);
 
-    memset(ske, 'F', sizeof(*ske));
-    silc_free(ske);
-  }
-}
 
-/* Return user context */
+/* Packet callback */
 
-void *silc_ske_get_context(SilcSKE ske)
+static SilcBool silc_ske_packet_receive(SilcPacketEngine engine,
+                                       SilcPacketStream stream,
+                                       SilcPacket packet,
+                                       void *callback_context,
+                                       void *app_context)
 {
-  return ske->user_data;
+  SilcSKE ske = callback_context;
+  ske->packet = packet;
+  silc_fsm_continue(&ske->fsm);
+  return TRUE;
 }
 
-/* Sets protocol callbacks */
-
-void silc_ske_set_callbacks(SilcSKE ske,
-                           SilcSKEVerifyCb verify_key,
-                           SilcSKECheckVersionCb check_version,
-                           SilcSKECompletionCb completed,
-                           void *context)
+/* Packet stream callbacks */
+static SilcPacketCallbacks silc_ske_stream_cbs =
 {
-  if (ske->callbacks)
-    silc_free(ske->callbacks);
-  ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
-  if (!ske->callbacks)
-    return;
-  ske->callbacks->verify_key = verify_key;
-  ske->callbacks->check_version = check_version;
-  ske->callbacks->completed = completed;
-  ske->callbacks->context = context;
-}
+  silc_ske_packet_receive, NULL, NULL
+};
 
 /* Aborts SKE protocol */
 
@@ -197,716 +81,831 @@ static void silc_ske_abort(SilcAsyncOperation op, void *context)
 static void silc_ske_pk_verified(SilcSKE ske, SilcSKEStatus status,
                                 void *completion_context)
 {
+  ske->status = status;
   SILC_FSM_CALL_CONTINUE(&ske->fsm);
 }
 
-/* Initiator state machine */
-SILC_FSM_STATE(silc_ske_st_initiator_start);
-SILC_FSM_STATE(silc_ske_st_initiator_phase1);
-SILC_FSM_STATE(silc_ske_st_initiator_phase2);
-SILC_FSM_STATE(silc_ske_st_initiator_phase3);
-SILC_FSM_STATE(silc_ske_st_initiator_phase4);
-SILC_FSM_STATE(silc_ske_st_initiator_end);
-SILC_FSM_STATE(silc_ske_st_initiator_aborted);
-SILC_FSM_STATE(silc_ske_st_initiator_error);
-
-/* Start protocol.  Send our proposal */
+/* Checks remote and local versions */
 
-SILC_FSM_STATE(silc_ske_st_initiator_start)
+static SilcSKEStatus silc_ske_check_version(SilcSKE ske)
 {
-  SilcSKE ske = fsm_context;
-  SilcBuffer payload_buf;
-  SilcStatus status;
+  SilcUInt32 l_protocol_version = 0, r_protocol_version = 0;
 
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
-    return SILC_FSM_CONTINUE;
-  }
+  if (!ske->remote_version || !ske->version)
+    return SILC_SKE_STATUS_BAD_VERSION;
 
-  /* Encode the payload */
-  status = silc_ske_payload_start_encode(ske, ske->start_payload,
-                                        &payload_buf);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error encoding Start Payload */
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
+  if (!silc_parse_version_string(ske->remote_version, &r_protocol_version,
+                                NULL, NULL, NULL, NULL))
+    return SILC_SKE_STATUS_BAD_VERSION;
 
-  /* Save the the payload buffer for future use. It is later used to
-     compute the HASH value. */
-  ske->start_payload_copy = payload_buf;
+  if (!silc_parse_version_string(ske->version, &l_protocol_version,
+                                NULL, NULL, NULL, NULL))
+    return SILC_SKE_STATUS_BAD_VERSION;
 
-  /* Send the packet */
-  /* XXX */
+  /* If remote is too new, don't connect */
+  if (l_protocol_version < r_protocol_version)
+    return SILC_SKE_STATUS_BAD_VERSION;
 
-  /** Wait for responder proposal */
-  SILC_LOG_DEBUG(("Waiting for reponder proposal"));
-  silc_fsm_next(ske, silc_ske_st_initiator_phase1);
-  return SILC_FSM_WAIT;
+  return SILC_SKE_STATUS_OK;
 }
 
-/* Phase-1.  Receives responder's proposal */
+/* Selects the supported security properties from the initiator's Key
+   Exchange Start Payload. */
 
-SILC_FSM_STATE(silc_ske_st_initiator_phase1)
+static SilcSKEStatus
+silc_ske_select_security_properties(SilcSKE ske,
+                                   SilcSKEStartPayload payload,
+                                   SilcSKEStartPayload remote_payload)
 {
-  SilcSKE ske = fsm_context;
   SilcSKEStatus status;
-  SilcSKEStartPayload payload;
-  SilcSKESecurityProperties prop;
-  SilcSKEDiffieHellmanGroup group;
+  SilcSKEStartPayload rp;
+  char *cp;
+  int len;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Parsing KE Start Payload"));
 
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
-    return SILC_FSM_CONTINUE;
-  }
+  rp = remote_payload;
 
-  /* Decode the payload */
-  status = silc_ske_payload_start_decode(ske, ske->packet_buf, &payload);
+  /* Check version string */
+  ske->remote_version = silc_memdup(rp->version, rp->version_len);
+  status = silc_ske_check_version(ske);
   if (status != SILC_SKE_STATUS_OK) {
-    /** Error decoding Start Payload */
     ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
+    return status;
   }
 
-  /* Check that the cookie is returned unmodified */
-  if (memcmp(ske->start_payload->cookie, payload->cookie,
-            ske->start_payload->cookie_len)) {
-    /** Invalid cookie */
-    SILC_LOG_ERROR(("Responder modified our cookie and it must not do it"));
-    ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
+  /* Flags are returned unchanged. */
+  payload->flags = rp->flags;
+
+  /* Take cookie, we must return it to sender unmodified. */
+  payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
+  if (!payload->cookie) {
+    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+    return status;
   }
+  payload->cookie_len = SILC_SKE_COOKIE_LEN;
+  memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
 
-  /* Check version string */
-  if (ske->callbacks->check_version) {
-    status = ske->callbacks->check_version(ske, payload->version,
-                                          payload->version_len,
-                                          ske->callbacks->context);
-    if (status != SILC_SKE_STATUS_OK) {
-      /** Version mismatch */
-      ske->status = status;
-      silc_fsm_next(fsm, silc_ske_st_initiator_error);
-      return SILC_FSM_CONTINUE;
-    }
+  /* Put our version to our reply */
+  payload->version = strdup(ske->version);
+  if (!payload->version) {
+    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+    return status;
   }
+  payload->version_len = strlen(ske->version);
 
-  /* Free our KE Start Payload context, we don't need it anymore. */
-  silc_ske_payload_start_free(ske->start_payload);
-  ske->start_payload = NULL;
+  /* Get supported Key Exchange groups */
+  cp = rp->ke_grp_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
 
-  /* Take the selected security properties into use while doing
-     the key exchange.  This is used only while doing the key
-     exchange. */
-  ske->prop = prop = silc_calloc(1, sizeof(*prop));
-  if (!ske->prop)
-    goto err;
-  prop->flags = payload->flags;
-  status = silc_ske_group_get_by_name(payload->ke_grp_list, &group);
-  if (status != SILC_SKE_STATUS_OK)
-    goto err;
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      if (!item) {
+       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+       return status;
+      }
+      memcpy(item, cp, len);
 
-  prop->group = group;
+      SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
 
-  if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
-    status = SILC_SKE_STATUS_UNKNOWN_PKCS;
-    goto err;
-  }
-  if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
-    status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
-    goto err;
-  }
-  if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
-    status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
-    goto err;
-  }
-  if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
-    status = SILC_SKE_STATUS_UNKNOWN_HMAC;
-    goto err;
-  }
+      if (silc_ske_group_get_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
+       SILC_LOG_DEBUG(("Found KE group `%s'", item));
 
-  /* Save remote's KE Start Payload */
-  ske->start_payload = payload;
+       payload->ke_grp_len = len;
+       payload->ke_grp_list = item;
+       break;
+      }
 
-  /** Send KE Payload */
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase2);
-  return SILC_FSM_CONTINUE;
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
 
- err:
-  if (payload)
-    silc_ske_payload_start_free(payload);
+      if (item)
+       silc_free(item);
+    }
 
-  silc_ske_group_free(group);
+    if (!payload->ke_grp_len && !payload->ke_grp_list) {
+      SILC_LOG_DEBUG(("Could not find supported KE group"));
+      silc_free(payload);
+      return SILC_SKE_STATUS_UNKNOWN_GROUP;
+    }
+  } else {
 
-  if (prop->pkcs)
-    silc_pkcs_free(prop->pkcs);
-  if (prop->cipher)
-    silc_cipher_free(prop->cipher);
-  if (prop->hash)
-    silc_hash_free(prop->hash);
-  if (prop->hmac)
-    silc_hmac_free(prop->hmac);
-  silc_free(prop);
-  ske->prop = NULL;
+    if (!rp->ke_grp_len) {
+      SILC_LOG_DEBUG(("KE group not defined in payload"));
+      silc_free(payload);
+      return SILC_SKE_STATUS_BAD_PAYLOAD;
+    }
 
-  if (status == SILC_SKE_STATUS_OK)
-    status = SILC_SKE_STATUS_ERROR;
+    SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
+    SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
 
-  /** Error */
-  ske->status = status;
-  silc_fsm_next(fsm, silc_ske_st_initiator_error);
-  return SILC_FSM_CONTINUE;
-}
+    payload->ke_grp_len = rp->ke_grp_len;
+    payload->ke_grp_list = strdup(rp->ke_grp_list);
+  }
 
-/* Phase-2.  Send KE payload */
+  /* Get supported PKCS algorithms */
+  cp = rp->pkcs_alg_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
 
-SILC_FSM_STATE(silc_ske_st_initiator_phase2)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcBuffer payload_buf;
-  SilcMPInt *x;
-  SilcSKEKEPayload payload;
-  SilcUInt32 pk_len;
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      if (!item) {
+       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+       return status;
+      }
+      memcpy(item, cp, len);
 
-  SILC_LOG_DEBUG(("Start"));
+      SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
 
-  /* Create the random number x, 1 < x < q. */
-  x = silc_calloc(1, sizeof(*x));
-  if (!x){
-    /** Out of memory */
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-  silc_mp_init(x);
-  status =
-    silc_ske_create_rnd(ske, &ske->prop->group->group_order,
-                       silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
-                       x);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error generating random number */
-    silc_mp_uninit(x);
-    silc_free(x);
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
+      if (silc_pkcs_is_supported(item) == TRUE) {
+       SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
 
-  /* Encode the result to Key Exchange Payload. */
+       payload->pkcs_alg_len = len;
+       payload->pkcs_alg_list = item;
+       break;
+      }
 
-  payload = silc_calloc(1, sizeof(*payload));
-  if (!payload) {
-    /** Out of memory */
-    silc_mp_uninit(x);
-    silc_free(x);
-    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-  ske->ke1_payload = payload;
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
 
-  SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
+      if (item)
+       silc_free(item);
+    }
 
-  /* Do the Diffie Hellman computation, e = g ^ x mod p */
-  silc_mp_init(&payload->x);
-  silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x,
-                 &ske->prop->group->group);
+    if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
+      SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_UNKNOWN_PKCS;
+    }
+  } else {
 
-  /* Get public key */
-  if (ske->public_key) {
-    payload->pk_data = silc_pkcs_public_key_encode(ske->public_key, &pk_len);
-    if (!payload->pk_data) {
-      /** Error encoding public key */
-      silc_mp_uninit(x);
-      silc_free(x);
-      silc_mp_uninit(&payload->x);
+    if (!rp->pkcs_alg_len) {
+      SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
+      silc_free(payload->ke_grp_list);
       silc_free(payload);
-      ske->ke1_payload = NULL;
-      ske->status = SILC_SKE_STATUS_ERROR;
-      silc_fsm_next(fsm, silc_ske_st_initiator_error);
-      return SILC_FSM_CONTINUE;
+      return SILC_SKE_STATUS_BAD_PAYLOAD;
     }
-    payload->pk_len = pk_len;
+
+    SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
+    SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
+
+    payload->pkcs_alg_len = rp->pkcs_alg_len;
+    payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
   }
-  payload->pk_type = ske->pk_type;
 
-  /* Compute signature data if we are doing mutual authentication */
-  if (ske->private_key &&
-      ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
-    unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1];
-    SilcUInt32 hash_len, sign_len;
+  /* Get supported encryption algorithms */
+  cp = rp->enc_alg_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
 
-    SILC_LOG_DEBUG(("We are doing mutual authentication"));
-    SILC_LOG_DEBUG(("Computing HASH_i value"));
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      if (!item) {
+       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+       return status;
+      }
+      memcpy(item, cp, len);
 
-    /* Compute the hash value */
-    memset(hash, 0, sizeof(hash));
-    silc_ske_make_hash(ske, hash, &hash_len, TRUE);
+      SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
 
-    SILC_LOG_DEBUG(("Signing HASH_i value"));
+      if (silc_cipher_is_supported(item) == TRUE) {
+       SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
 
-    /* Sign the hash value */
-    silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv,
-                                  ske->private_key->prv_len);
-    if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
-       !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
-      /** Error computing signature */
-      silc_mp_uninit(x);
-      silc_free(x);
-      silc_mp_uninit(&payload->x);
-      silc_free(payload->pk_data);
+       payload->enc_alg_len = len;
+       payload->enc_alg_list = item;
+       break;
+      }
+
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
+
+      if (item)
+       silc_free(item);
+    }
+
+    if (!payload->enc_alg_len && !payload->enc_alg_list) {
+      SILC_LOG_DEBUG(("Could not find supported encryption alg"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
       silc_free(payload);
-      ske->ke1_payload = NULL;
-      ske->status = SILC_SKE_STATUS_SIGNATURE_ERROR;
-      silc_fsm_next(fsm, silc_ske_st_initiator_error);
-      return SILC_FSM_CONTINUE;
+      return SILC_SKE_STATUS_UNKNOWN_CIPHER;
     }
-    payload->sign_data = silc_memdup(sign, sign_len);
-    payload->sign_len = sign_len;
-    memset(sign, 0, sizeof(sign));
-  }
+  } else {
 
-  status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error encoding KE payload */
-    silc_mp_uninit(x);
-    silc_free(x);
-    silc_mp_uninit(&payload->x);
-    silc_free(payload->pk_data);
-    silc_free(payload->sign_data);
-    silc_free(payload);
-    ske->ke1_payload = NULL;
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
+    if (!rp->enc_alg_len) {
+      SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_BAD_PAYLOAD;
+    }
 
-  ske->x = x;
+    SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
+                   rp->enc_alg_list));
 
-  /* Send the packet. */
-  /* XXX */
+    payload->enc_alg_len = rp->enc_alg_len;
+    payload->enc_alg_list = strdup(rp->enc_alg_list);
+  }
 
-  silc_buffer_free(payload_buf);
+  /* Get supported hash algorithms */
+  cp = rp->hash_alg_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
 
-  /** Waiting responder's KE payload */
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase3);
-  return SILC_FSM_WAIT;
-}
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      if (!item) {
+       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+       return status;
+      }
+      memcpy(item, cp, len);
 
-/* Phase-3.  Process responder's KE payload */
+      SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
 
-SILC_FSM_STATE(silc_ske_st_initiator_phase3)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcSKEKEPayload payload;
-  SilcMPInt *KEY;
+      if (silc_hash_is_supported(item) == TRUE) {
+       SILC_LOG_DEBUG(("Found hash alg `%s'", item));
 
-  SILC_LOG_DEBUG(("Start"));
+       payload->hash_alg_len = len;
+       payload->hash_alg_list = item;
+       break;
+      }
 
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
-    return SILC_FSM_CONTINUE;
-  }
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
 
-  /* Decode the payload */
-  status = silc_ske_payload_ke_decode(ske, ske->packet_buf, &payload);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error decoding KE payload */
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
-  ske->ke2_payload = payload;
+      if (item)
+       silc_free(item);
+    }
 
-  if (!payload->pk_data && ske->callbacks->verify_key) {
-    SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
-                   "even though we require it"));
-    ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
-    goto err;
+    if (!payload->hash_alg_len && !payload->hash_alg_list) {
+      SILC_LOG_DEBUG(("Could not find supported hash alg"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload->enc_alg_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+    }
+  } else {
+
+    if (!rp->hash_alg_len) {
+      SILC_LOG_DEBUG(("Hash alg not defined in payload"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload->enc_alg_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_BAD_PAYLOAD;
+    }
+
+    SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
+                   rp->hash_alg_list));
+
+    payload->hash_alg_len = rp->hash_alg_len;
+    payload->hash_alg_list = strdup(rp->hash_alg_list);
   }
 
-  SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
+  /* Get supported HMACs */
+  cp = rp->hmac_alg_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
 
-  /* Compute the shared secret key */
-  KEY = silc_calloc(1, sizeof(*KEY));
-  silc_mp_init(KEY);
-  silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
-  ske->KEY = KEY;
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      if (!item) {
+       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+       return status;
+      }
+      memcpy(item, cp, len);
 
-  if (payload->pk_data && ske->callbacks->verify_key) {
-    SILC_LOG_DEBUG(("Verifying public key"));
+      SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
 
-    /** Waiting public key verification */
-    silc_fsm_next(fsm, silc_ske_st_initiator_phase4);
-    SILC_FSM_CALL(ske->callbacks->verify_key(ske, payload->pk_data,
-                                            payload->pk_len,
-                                            payload->pk_type,
-                                            ske->callbacks->context,
-                                            silc_ske_pk_verified, NULL));
-    /* NOT REACHED */
+      if (silc_hmac_is_supported(item) == TRUE) {
+       SILC_LOG_DEBUG(("Found HMAC `%s'", item));
+
+       payload->hmac_alg_len = len;
+       payload->hmac_alg_list = item;
+       break;
+      }
+
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
+
+      if (item)
+       silc_free(item);
+    }
+
+    if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
+      SILC_LOG_DEBUG(("Could not find supported HMAC"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload->enc_alg_list);
+      silc_free(payload->hash_alg_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_UNKNOWN_HMAC;
+    }
+  } else {
+
+    if (!rp->hmac_alg_len) {
+      SILC_LOG_DEBUG(("HMAC not defined in payload"));
+      silc_free(payload->ke_grp_list);
+      silc_free(payload->pkcs_alg_list);
+      silc_free(payload->enc_alg_list);
+      silc_free(payload->hash_alg_list);
+      silc_free(payload);
+      return SILC_SKE_STATUS_BAD_PAYLOAD;
+    }
+
+    SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
+                   rp->hmac_alg_list));
+
+    payload->hmac_alg_len = rp->hmac_alg_len;
+    payload->hmac_alg_list = strdup(rp->hmac_alg_list);
   }
 
-  /** Process key material */
-  silc_fsm_next(fsm, silc_ske_st_initiator_phase4);
-  return SILC_FSM_CONTINUE;
+  /* Get supported compression algorithms */
+  cp = rp->comp_alg_list;
+  if (cp && strchr(cp, ',')) {
+    while(cp) {
+      char *item;
 
- err:
-  silc_ske_payload_ke_free(payload);
-  ske->ke2_payload = NULL;
+      len = strcspn(cp, ",");
+      item = silc_calloc(len + 1, sizeof(char));
+      if (!item) {
+       ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+       return status;
+      }
+      memcpy(item, cp, len);
 
-  silc_mp_uninit(ske->KEY);
-  silc_free(ske->KEY);
-  ske->KEY = NULL;
+      SILC_LOG_DEBUG(("Proposed Compression `%s'", item));
 
-  if (status == SILC_SKE_STATUS_OK)
-    return SILC_SKE_STATUS_ERROR;
+#if 1
+      if (!strcmp(item, "none")) {
+       SILC_LOG_DEBUG(("Found Compression `%s'", item));
+       payload->comp_alg_len = len;
+       payload->comp_alg_list = item;
+       break;
+      }
+#else
+      if (silc_hmac_is_supported(item) == TRUE) {
+       SILC_LOG_DEBUG(("Found Compression `%s'", item));
+       payload->comp_alg_len = len;
+       payload->comp_alg_list = item;
+       break;
+      }
+#endif
 
-  /** Error */
-  ske->status = status;
-  silc_fsm_next(fsm, silc_ske_st_initiator_error);
-  return SILC_FSM_CONTINUE;
+      cp += len;
+      if (strlen(cp) == 0)
+       cp = NULL;
+      else
+       cp++;
+
+      if (item)
+       silc_free(item);
+    }
+  }
+
+  payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
+    2 + payload->version_len +
+    2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
+    2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
+    2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
+
+  return SILC_SKE_STATUS_OK;
 }
 
-/* Process key material */
+/* Creates random number such that 1 < rnd < n and at most length
+   of len bits. The rnd sent as argument must be initialized. */
 
-SILC_FSM_STATE(silc_ske_st_initiator_phase4)
+static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
+                                        SilcUInt32 len,
+                                        SilcMPInt *rnd)
 {
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcSKEKEPayload payload;
-  unsigned char hash[SILC_HASH_MAXLEN];
-  SilcUInt32 hash_len;
-  SilcPublicKey public_key = NULL;
-  int key_len, block_len;
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  unsigned char *string;
+  SilcUInt32 l;
 
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
-    return SILC_FSM_CONTINUE;
-  }
+  if (!len)
+    return SILC_SKE_STATUS_ERROR;
 
-  /* Check result of public key verification */
-  if (ske->status != SILC_SKE_STATUS_OK) {
-    /** Public key not verified */
-    SILC_LOG_DEBUG(("Public key verification failed"));
-    silc_fsm_next(fsm, silc_ske_st_initiator_error);
-    return SILC_FSM_CONTINUE;
-  }
+  SILC_LOG_DEBUG(("Creating random number"));
 
-  payload = ske->ke2_payload;
+  l = ((len - 1) / 8);
 
-  if (payload->pk_data) {
-    /* Decode the public key */
-    if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
-                                    &public_key)) {
-      SILC_LOG_ERROR(("Unsupported/malformed public key received"));
-      status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
-      goto err;
-    }
+  /* Get the random number as string */
+  string = silc_rng_get_rn_data(ske->rng, l);
+  if (!string)
+    return SILC_SKE_STATUS_OUT_OF_MEMORY;
 
-    SILC_LOG_DEBUG(("Public key is authentic"));
+  /* Decode the string into a MP integer */
+  silc_mp_bin2mp(string, l, rnd);
+  silc_mp_mod_2exp(rnd, rnd, len);
 
-    /* Compute the hash value */
-    status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
-    if (status != SILC_SKE_STATUS_OK)
-      goto err;
+  /* Checks */
+  if (silc_mp_cmp_ui(rnd, 1) < 0)
+    status = SILC_SKE_STATUS_ERROR;
+  if (silc_mp_cmp(rnd, n) >= 0)
+    status = SILC_SKE_STATUS_ERROR;
 
-    ske->hash = silc_memdup(hash, hash_len);
-    ske->hash_len = hash_len;
+  memset(string, 'F', l);
+  silc_free(string);
 
-    SILC_LOG_DEBUG(("Verifying signature (HASH)"));
+  return status;
+}
 
-    /* Verify signature */
-    silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
-    if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
-                        payload->sign_len, hash, hash_len) == FALSE) {
-      SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
-      status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
-      goto err;
-    }
+/* Creates a hash value HASH as defined in the SKE protocol. If the
+   `initiator' is TRUE then this function is used to create the HASH_i
+   hash value defined in the protocol. If it is FALSE then this is used
+   to create the HASH value defined by the protocol. */
 
-    SILC_LOG_DEBUG(("Signature is Ok"));
+static SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
+                                       unsigned char *return_hash,
+                                       SilcUInt32 *return_hash_len,
+                                       int initiator)
+{
+  SilcSKEStatus status = SILC_SKE_STATUS_OK;
+  SilcBuffer buf;
+  unsigned char *e, *f, *KEY;
+  SilcUInt32 e_len, f_len, KEY_len;
+  int ret;
 
-    silc_pkcs_public_key_free(public_key);
-    memset(hash, 'F', hash_len);
-  }
+  SILC_LOG_DEBUG(("Start"));
 
-  ske->status = SILC_SKE_STATUS_OK;
+  if (initiator == FALSE) {
+    e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
+    f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
+    KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
 
-  /* Process key material */
-  key_len = silc_cipher_get_key_len(ske->prop->cipher);
-  block_len = silc_cipher_get_key_len(ske->prop->cipher);
-  hash_len = silc_hash_len(ske->prop->hash);
-  ske->keymat = silc_ske_process_key_material(ske, block_len,
-                                             key_len, hash_len);
-  if (!ske->keymat) {
-    SILC_LOG_ERROR(("Error processing key material"));
-    status = SILC_SKE_STATUS_ERROR;
-    goto err;
-  }
+    /* Format the buffer used to compute the hash value */
+    buf = silc_buffer_alloc_size(silc_buffer_len(ske->start_payload_copy) +
+                                ske->ke2_payload->pk_len +
+                                ske->ke1_payload->pk_len +
+                                e_len + f_len + KEY_len);
+    if (!buf)
+      return SILC_SKE_STATUS_OUT_OF_MEMORY;
 
-  /* Send SUCCESS packet */
-  /* XXX */
+    /* Initiator is not required to send its public key */
+    if (!ske->ke1_payload->pk_data) {
+      ret =
+       silc_buffer_format(buf,
+                          SILC_STR_UI_XNSTRING(
+                                  ske->start_payload_copy->data,
+                                  silc_buffer_len(ske->start_payload_copy)),
+                          SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
+                                               ske->ke2_payload->pk_len),
+                          SILC_STR_UI_XNSTRING(e, e_len),
+                          SILC_STR_UI_XNSTRING(f, f_len),
+                          SILC_STR_UI_XNSTRING(KEY, KEY_len),
+                          SILC_STR_END);
+    } else {
+      ret =
+       silc_buffer_format(buf,
+                          SILC_STR_UI_XNSTRING(
+                                  ske->start_payload_copy->data,
+                                  silc_buffer_len(ske->start_payload_copy)),
+                          SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
+                                               ske->ke2_payload->pk_len),
+                          SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
+                                               ske->ke1_payload->pk_len),
+                          SILC_STR_UI_XNSTRING(e, e_len),
+                          SILC_STR_UI_XNSTRING(f, f_len),
+                          SILC_STR_UI_XNSTRING(KEY, KEY_len),
+                          SILC_STR_END);
+    }
+    if (ret == -1) {
+      silc_buffer_free(buf);
+      memset(e, 0, e_len);
+      memset(f, 0, f_len);
+      memset(KEY, 0, KEY_len);
+      silc_free(e);
+      silc_free(f);
+      silc_free(KEY);
+      return SILC_SKE_STATUS_ERROR;
+    }
 
-  /** Waiting completion */
-  silc_fsm_next(fsm, silc_ske_st_initiator_end);
-  return SILC_FSM_WAIT;
+    memset(e, 0, e_len);
+    memset(f, 0, f_len);
+    memset(KEY, 0, KEY_len);
+    silc_free(e);
+    silc_free(f);
+    silc_free(KEY);
+  } else {
+    e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
 
- err:
-  memset(hash, 'F', sizeof(hash));
-  silc_ske_payload_ke_free(payload);
-  ske->ke2_payload = NULL;
+    buf = silc_buffer_alloc_size(silc_buffer_len(ske->start_payload_copy) +
+                                ske->ke1_payload->pk_len + e_len);
+    if (!buf)
+      return SILC_SKE_STATUS_OUT_OF_MEMORY;
 
-  silc_mp_uninit(ske->KEY);
-  silc_free(ske->KEY);
-  ske->KEY = NULL;
+    /* Format the buffer used to compute the hash value */
+    ret =
+      silc_buffer_format(buf,
+                        SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+                                    silc_buffer_len(ske->start_payload_copy)),
+                        SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
+                                             ske->ke1_payload->pk_len),
+                        SILC_STR_UI_XNSTRING(e, e_len),
+                        SILC_STR_END);
+    if (ret == -1) {
+      silc_buffer_free(buf);
+      memset(e, 0, e_len);
+      silc_free(e);
+      return SILC_SKE_STATUS_ERROR;
+    }
+
+    memset(e, 0, e_len);
+    silc_free(e);
+  }
 
-  if (public_key)
-    silc_pkcs_public_key_free(public_key);
+  /* Make the hash */
+  silc_hash_make(ske->prop->hash, buf->data, silc_buffer_len(buf),
+                return_hash);
+  *return_hash_len = silc_hash_len(ske->prop->hash);
 
-  if (ske->hash) {
-    memset(ske->hash, 'F', hash_len);
-    silc_free(ske->hash);
-    ske->hash = NULL;
+  if (initiator == FALSE) {
+    SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
+  } else {
+    SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
   }
 
-  if (status == SILC_SKE_STATUS_OK)
-    status = SILC_SKE_STATUS_ERROR;
+  silc_buffer_free(buf);
 
-  /** Error */
-  ske->status = status;
-  silc_fsm_next(fsm, silc_ske_st_initiator_error);
-  return SILC_FSM_CONTINUE;
+  return status;
 }
 
-/* Protocol completed */
 
-SILC_FSM_STATE(silc_ske_st_initiator_end)
-{
-  SilcSKE ske = fsm_context;
+/******************************* Protocol API *******************************/
 
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
-    return SILC_FSM_CONTINUE;
-  }
+/* Allocates new SKE object. */
 
-  /* Call the completion callback */
-  if (ske->callbacks->completed)
-    ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL, NULL);
+SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
+                      SilcPublicKey public_key, SilcPrivateKey private_key,
+                      void *context)
+{
+  SilcSKE ske;
 
-  return SILC_FSM_FINISH;
-}
+  SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
 
-/* Aborted by application */
+  if (!rng || !schedule)
+    return NULL;
 
-SILC_FSM_STATE(silc_ske_st_initiator_aborted)
-{
+  ske = silc_calloc(1, sizeof(*ske));
+  if (!ske)
+    return NULL;
+  ske->status = SILC_SKE_STATUS_OK;
+  ske->rng = rng;
+  ske->user_data = context;
+  ske->schedule = schedule;
+  ske->public_key = public_key;
+  ske->private_key = private_key;
+  ske->pk_type = SILC_SKE_PK_TYPE_SILC;
 
-  return SILC_FSM_FINISH;
+  return ske;
 }
 
-/* Error occurred */
+/* Free's SKE object. */
 
-SILC_FSM_STATE(silc_ske_st_initiator_error)
+void silc_ske_free(SilcSKE ske)
 {
+  SILC_LOG_DEBUG(("Freeing Key Exchange object"));
 
-  return SILC_FSM_FINISH;
-}
+  if (ske) {
+    /* Free start payload */
+    if (ske->start_payload)
+      silc_ske_payload_start_free(ske->start_payload);
 
+    /* Free KE payload */
+    if (ske->ke1_payload)
+      silc_ske_payload_ke_free(ske->ke1_payload);
+    if (ske->ke2_payload)
+      silc_ske_payload_ke_free(ske->ke2_payload);
+    silc_free(ske->remote_version);
 
-static void silc_ske_initiator_finished(SilcFSM fsm, void *fsm_context,
-                                       void *destructor_context)
-{
+    /* Free rest */
+    if (ske->prop) {
+      if (ske->prop->group)
+       silc_ske_group_free(ske->prop->group);
+      if (ske->prop->pkcs)
+       silc_pkcs_free(ske->prop->pkcs);
+      if (ske->prop->cipher)
+       silc_cipher_free(ske->prop->cipher);
+      if (ske->prop->hash)
+       silc_hash_free(ske->prop->hash);
+      if (ske->prop->hmac)
+       silc_hmac_free(ske->prop->hmac);
+      silc_free(ske->prop);
+    }
+    if (ske->start_payload_copy)
+      silc_buffer_free(ske->start_payload_copy);
+    if (ske->x) {
+      silc_mp_uninit(ske->x);
+      silc_free(ske->x);
+    }
+    if (ske->KEY) {
+      silc_mp_uninit(ske->KEY);
+      silc_free(ske->KEY);
+    }
+    silc_free(ske->hash);
+    silc_free(ske->callbacks);
 
+    memset(ske, 'F', sizeof(*ske));
+    silc_free(ske);
+  }
 }
 
-/* Starts the protocol as initiator */
+/* Return user context */
 
-SilcAsyncOperation
-silc_ske_initiator_start(SilcSKE ske,
-                        SilcPacketStream stream,
-                        SilcSKEStartPayload start_payload)
+void *silc_ske_get_context(SilcSKE ske)
 {
-  SILC_LOG_DEBUG(("Start SKE as initiator"));
-
-  if (!ske || !stream || !start_payload)
-    return NULL;
-
-  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
-    return NULL;
-
-  if (!silc_fsm_init(&ske->fsm, ske, silc_ske_initiator_finished, ske,
-                    ske->schedule))
-    return NULL;
+  return ske->user_data;
+}
 
-  ske->start_payload = start_payload;
+/* Sets protocol callbacks */
 
-  /* Link to packet stream to get key exchange packets */
-  ske->stream = stream;
-  silc_packet_stream_ref(ske->stream);
-  silc_packet_stream_callbacks(ske->stream, &silc_ske_stream_cbs, ske);
+void silc_ske_set_callbacks(SilcSKE ske,
+                           SilcSKEVerifyCb verify_key,
+                           SilcSKECompletionCb completed,
+                           void *context)
+{
+  if (ske->callbacks)
+    silc_free(ske->callbacks);
+  ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
+  if (!ske->callbacks)
+    return;
+  ske->callbacks->verify_key = verify_key;
+  ske->callbacks->completed = completed;
+  ske->callbacks->context = context;
+}
 
-  /* Start SKE as initiator */
-  silc_fsm_start(&ske->fsm, silc_ske_st_initiator_start);
 
-  return &ske->op;
-}
+/******************************** Initiator *********************************/
 
-/* Responder state machine */
-SILC_FSM_STATE(silc_ske_st_responder_start);
-SILC_FSM_STATE(silc_ske_st_responder_phase1);
-SILC_FSM_STATE(silc_ske_st_responder_phase2);
-SILC_FSM_STATE(silc_ske_st_responder_phase3);
-SILC_FSM_STATE(silc_ske_st_responder_phase4);
-SILC_FSM_STATE(silc_ske_st_responder_end);
-SILC_FSM_STATE(silc_ske_st_responder_aborted);
-SILC_FSM_STATE(silc_ske_st_responder_error);
+/* Initiator state machine */
+SILC_FSM_STATE(silc_ske_st_initiator_start);
+SILC_FSM_STATE(silc_ske_st_initiator_phase1);
+SILC_FSM_STATE(silc_ske_st_initiator_phase2);
+SILC_FSM_STATE(silc_ske_st_initiator_phase3);
+SILC_FSM_STATE(silc_ske_st_initiator_phase4);
+SILC_FSM_STATE(silc_ske_st_initiator_end);
+SILC_FSM_STATE(silc_ske_st_initiator_aborted);
+SILC_FSM_STATE(silc_ske_st_initiator_error);
 
-/* Start protocol as responder.  Decode initiator's start payload */
+/* Start protocol.  Send our proposal */
 
-SILC_FSM_STATE(silc_ske_st_responder_start)
+SILC_FSM_STATE(silc_ske_st_initiator_start)
 {
   SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcSKEStartPayload remote_payload = NULL, payload = NULL;
+  SilcBuffer payload_buf;
+  SilcStatus status;
 
   SILC_LOG_DEBUG(("Start"));
 
   if (ske->aborted) {
     /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
+    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
     return SILC_FSM_CONTINUE;
   }
 
-  /* Decode the payload */
-  status = silc_ske_payload_start_decode(ske, ske->packet_buf,
-                                        &remote_payload);
+  /* Encode the payload */
+  status = silc_ske_payload_start_encode(ske, ske->start_payload,
+                                        &payload_buf);
   if (status != SILC_SKE_STATUS_OK) {
-    /** Error decoding Start Payload */
+    /** Error encoding Start Payload */
     ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
     return SILC_FSM_CONTINUE;
   }
 
-  /* Take a copy of the payload buffer for future use. It is used to
+  /* Save the the payload buffer for future use. It is later used to
      compute the HASH value. */
-  ske->start_payload_copy = silc_buffer_copy(ske->packet_buf);
+  ske->start_payload_copy = payload_buf;
 
-  /* Force the mutual authentication flag if we want to do it. */
-  if (ske->flags & SILC_SKE_SP_FLAG_MUTUAL) {
-    SILC_LOG_DEBUG(("Force mutual authentication"));
-    remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
-  }
+  /* Send the packet */
+  /* XXX */
 
-  /* Force PFS flag if we require it */
-  if (ske->flags & SILC_SKE_SP_FLAG_PFS) {
-    SILC_LOG_DEBUG(("Force PFS"));
-    remote_payload->flags |= SILC_SKE_SP_FLAG_PFS;
-  }
+  /** Wait for responder proposal */
+  SILC_LOG_DEBUG(("Waiting for reponder proposal"));
+  silc_fsm_next(ske, silc_ske_st_initiator_phase1);
+  return SILC_FSM_WAIT;
+}
 
-  /* Disable IV Included flag if requested */
-  if (remote_payload->flags & SILC_SKE_SP_FLAG_IV_INCLUDED &&
-      !(ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)) {
-    SILC_LOG_DEBUG(("We do not support IV Included flag"));
-    remote_payload->flags &= ~SILC_SKE_SP_FLAG_IV_INCLUDED;
+/* Phase-1.  Receives responder's proposal */
+
+SILC_FSM_STATE(silc_ske_st_initiator_phase1)
+{
+  SilcSKE ske = fsm_context;
+  SilcSKEStatus status;
+  SilcSKEStartPayload payload;
+  SilcSKESecurityProperties prop;
+  SilcSKEDiffieHellmanGroup group;
+  SilcBuffer packet_buf = &ske->packet->buffer;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (ske->aborted) {
+    /** Aborted */
+    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
+    return SILC_FSM_CONTINUE;
   }
 
-  /* Parse and select the security properties from the payload */
-  payload = silc_calloc(1, sizeof(*payload));
-  status = silc_ske_select_security_properties(ske, ske->version,
-                                              payload, remote_payload);
+  /* Decode the payload */
+  status = silc_ske_payload_start_decode(ske, packet_buf, &payload);
   if (status != SILC_SKE_STATUS_OK) {
-    /** Error selecting proposal */
-    if (remote_payload)
-      silc_ske_payload_start_free(remote_payload);
-    silc_free(payload);
+    /** Error decoding Start Payload */
     ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
     return SILC_FSM_CONTINUE;
   }
 
-  ske->start_payload = payload;
-
-  silc_ske_payload_start_free(remote_payload);
-
-  /** Send proposal to initiator */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase1);
-  return SILC_FSM_CONTINUE;
-}
-
-/* Phase-1.  Send Start Payload */
+  /* Check that the cookie is returned unmodified */
+  if (memcmp(ske->start_payload->cookie, payload->cookie,
+            ske->start_payload->cookie_len)) {
+    /** Invalid cookie */
+    SILC_LOG_ERROR(("Responder modified our cookie and it must not do it"));
+    ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-SILC_FSM_STATE(silc_ske_st_responder_phase1)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcBuffer payload_buf;
-  SilcSKESecurityProperties prop;
-  SilcSKEDiffieHellmanGroup group = NULL;
+  /* Check version string */
+  ske->remote_version = silc_memdup(payload->version, payload->version_len);
+  status = silc_ske_check_version(ske);
+  if (status != SILC_SKE_STATUS_OK) {
+    /** Version mismatch */
+    ske->status = status;
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-  SILC_LOG_DEBUG(("Start"));
+  /* Free our KE Start Payload context, we don't need it anymore. */
+  silc_ske_payload_start_free(ske->start_payload);
+  ske->start_payload = NULL;
 
-  /* Allocate security properties from the payload. These are allocated
-     only for this negotiation and will be free'd after KE is over. */
+  /* Take the selected security properties into use while doing
+     the key exchange.  This is used only while doing the key
+     exchange. */
   ske->prop = prop = silc_calloc(1, sizeof(*prop));
-  prop->flags = ske->start_payload->flags;
-  status = silc_ske_group_get_by_name(ske->start_payload->ke_grp_list, &group);
+  if (!ske->prop)
+    goto err;
+  prop->flags = payload->flags;
+  status = silc_ske_group_get_by_name(payload->ke_grp_list, &group);
   if (status != SILC_SKE_STATUS_OK)
     goto err;
 
   prop->group = group;
 
-  if (silc_pkcs_alloc(ske->start_payload->pkcs_alg_list,
+  if (silc_pkcs_alloc(payload->pkcs_alg_list, ske->pk_type,
                      &prop->pkcs) == FALSE) {
     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
     goto err;
   }
-  if (silc_cipher_alloc(ske->start_payload->enc_alg_list,
-                       &prop->cipher) == FALSE) {
+  if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
     goto err;
   }
-  if (silc_hash_alloc(ske->start_payload->hash_alg_list,
-                     &prop->hash) == FALSE) {
+  if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
     goto err;
   }
-  if (silc_hmac_alloc(ske->start_payload->hmac_alg_list, NULL,
-                     &prop->hmac) == FALSE) {
+  if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
     status = SILC_SKE_STATUS_UNKNOWN_HMAC;
     goto err;
   }
 
-  /* Encode the payload */
-  status = silc_ske_payload_start_encode(ske, ske->start_payload,
-                                        &payload_buf);
-  if (status != SILC_SKE_STATUS_OK)
-    goto err;
-
-  /* Send the packet. */
-  /* XXX */
-
-  silc_buffer_free(payload_buf);
+  /* Save remote's KE Start Payload */
+  ske->start_payload = payload;
 
-  /** Waiting initiator's KE payload */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase2);
-  return SILC_FSM_WAIT;
+  /** Send KE Payload */
+  silc_fsm_next(fsm, silc_ske_st_initiator_phase2);
+  return SILC_FSM_CONTINUE;
 
  err:
-  if (group)
-    silc_ske_group_free(group);
+  if (payload)
+    silc_ske_payload_start_free(payload);
+
+  silc_ske_group_free(group);
 
   if (prop->pkcs)
     silc_pkcs_free(prop->pkcs);
@@ -924,84 +923,238 @@ SILC_FSM_STATE(silc_ske_st_responder_phase1)
 
   /** Error */
   ske->status = status;
-  silc_fsm_next(fsm, silc_ske_st_responder_error);
+  silc_fsm_next(fsm, silc_ske_st_initiator_error);
   return SILC_FSM_CONTINUE;
 }
 
-/* Phase-2.  Decode initiator's KE payload */
+/* Phase-2.  Send KE payload */
 
-SILC_FSM_STATE(silc_ske_st_responder_phase2)
+SILC_FSM_STATE(silc_ske_st_initiator_phase2)
 {
   SilcSKE ske = fsm_context;
   SilcSKEStatus status;
-  SilcSKEKEPayload recv_payload;
+  SilcBuffer payload_buf;
+  SilcMPInt *x;
+  SilcSKEKEPayload payload;
+  SilcUInt32 pk_len;
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (ske->aborted) {
-    /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
+  /* Create the random number x, 1 < x < q. */
+  x = silc_calloc(1, sizeof(*x));
+  if (!x){
+    /** Out of memory */
+    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
     return SILC_FSM_CONTINUE;
   }
-
-  /* Decode Key Exchange Payload */
-  status = silc_ske_payload_ke_decode(ske, ske->packet_buf, &recv_payload);
+  silc_mp_init(x);
+  status =
+    silc_ske_create_rnd(ske, &ske->prop->group->group_order,
+                       silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
+                       x);
   if (status != SILC_SKE_STATUS_OK) {
-    /** Error decoding KE payload */
+    /** Error generating random number */
+    silc_mp_uninit(x);
+    silc_free(x);
     ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
     return SILC_FSM_CONTINUE;
   }
 
-  ske->ke1_payload = recv_payload;
+  /* Encode the result to Key Exchange Payload. */
 
-  /* Verify the received public key and verify the signature if we are
-     doing mutual authentication. */
-  if (ske->start_payload &&
+  payload = silc_calloc(1, sizeof(*payload));
+  if (!payload) {
+    /** Out of memory */
+    silc_mp_uninit(x);
+    silc_free(x);
+    ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
+    return SILC_FSM_CONTINUE;
+  }
+  ske->ke1_payload = payload;
+
+  SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
+
+  /* Do the Diffie Hellman computation, e = g ^ x mod p */
+  silc_mp_init(&payload->x);
+  silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x,
+                 &ske->prop->group->group);
+
+  /* Get public key */
+  if (ske->public_key) {
+    payload->pk_data = silc_pkcs_public_key_encode(ske->public_key, &pk_len);
+    if (!payload->pk_data) {
+      /** Error encoding public key */
+      silc_mp_uninit(x);
+      silc_free(x);
+      silc_mp_uninit(&payload->x);
+      silc_free(payload);
+      ske->ke1_payload = NULL;
+      ske->status = SILC_SKE_STATUS_ERROR;
+      silc_fsm_next(fsm, silc_ske_st_initiator_error);
+      return SILC_FSM_CONTINUE;
+    }
+    payload->pk_len = pk_len;
+  }
+  payload->pk_type = ske->pk_type;
+
+  /* Compute signature data if we are doing mutual authentication */
+  if (ske->private_key &&
       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
+    unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1];
+    SilcUInt32 hash_len, sign_len;
 
     SILC_LOG_DEBUG(("We are doing mutual authentication"));
+    SILC_LOG_DEBUG(("Computing HASH_i value"));
 
-    if (!recv_payload->pk_data && ske->callbacks->verify_key) {
-      /** Public key not provided */
-      SILC_LOG_ERROR(("Remote end did not send its public key (or "
-                     "certificate), even though we require it"));
-      ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
+    /* Compute the hash value */
+    memset(hash, 0, sizeof(hash));
+    silc_ske_make_hash(ske, hash, &hash_len, TRUE);
+
+    SILC_LOG_DEBUG(("Signing HASH_i value"));
+
+    /* Sign the hash value */
+    silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv,
+                                  ske->private_key->prv_len);
+    if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
+       !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
+      /** Error computing signature */
+      silc_mp_uninit(x);
+      silc_free(x);
+      silc_mp_uninit(&payload->x);
+      silc_free(payload->pk_data);
+      silc_free(payload);
+      ske->ke1_payload = NULL;
+      ske->status = SILC_SKE_STATUS_SIGNATURE_ERROR;
+      silc_fsm_next(fsm, silc_ske_st_initiator_error);
       return SILC_FSM_CONTINUE;
     }
+    payload->sign_data = silc_memdup(sign, sign_len);
+    payload->sign_len = sign_len;
+    memset(sign, 0, sizeof(sign));
+  }
 
-    if (recv_payload->pk_data && ske->callbacks->verify_key) {
-      SILC_LOG_DEBUG(("Verifying public key"));
+  status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
+  if (status != SILC_SKE_STATUS_OK) {
+    /** Error encoding KE payload */
+    silc_mp_uninit(x);
+    silc_free(x);
+    silc_mp_uninit(&payload->x);
+    silc_free(payload->pk_data);
+    silc_free(payload->sign_data);
+    silc_free(payload);
+    ske->ke1_payload = NULL;
+    ske->status = status;
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-      /** Waiting public key verification */
-      silc_fsm_next(fsm, silc_ske_st_responder_phase3);
-      SILC_FSM_CALL(ske->callbacks->verify_key(ske, recv_payload->pk_data,
-                                              recv_payload->pk_len,
-                                              recv_payload->pk_type,
-                                              ske->callbacks->context,
-                                              silc_ske_pk_verified, NULL));
-      /* NOT REACHED */
-    }
+  ske->x = x;
+
+  /* Send the packet. */
+  /* XXX */
+
+  silc_buffer_free(payload_buf);
+
+  /** Waiting responder's KE payload */
+  silc_fsm_next(fsm, silc_ske_st_initiator_phase3);
+  return SILC_FSM_WAIT;
+}
+
+/* Phase-3.  Process responder's KE payload */
+
+SILC_FSM_STATE(silc_ske_st_initiator_phase3)
+{
+  SilcSKE ske = fsm_context;
+  SilcSKEStatus status;
+  SilcSKEKEPayload payload;
+  SilcMPInt *KEY;
+  SilcBuffer packet_buf = &ske->packet->buffer;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (ske->aborted) {
+    /** Aborted */
+    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Decode the payload */
+  status = silc_ske_payload_ke_decode(ske, packet_buf, &payload);
+  if (status != SILC_SKE_STATUS_OK) {
+    /** Error decoding KE payload */
+    ske->status = status;
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
+    return SILC_FSM_CONTINUE;
+  }
+  ske->ke2_payload = payload;
+
+  if (!payload->pk_data && ske->callbacks->verify_key) {
+    SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
+                   "even though we require it"));
+    ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
+    goto err;
+  }
+
+  SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
+
+  /* Compute the shared secret key */
+  KEY = silc_calloc(1, sizeof(*KEY));
+  silc_mp_init(KEY);
+  silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
+  ske->KEY = KEY;
+
+  if (payload->pk_data && ske->callbacks->verify_key) {
+    SILC_LOG_DEBUG(("Verifying public key"));
+
+    /** Waiting public key verification */
+    silc_fsm_next(fsm, silc_ske_st_initiator_phase4);
+    SILC_FSM_CALL(ske->callbacks->verify_key(ske, payload->pk_data,
+                                            payload->pk_len,
+                                            payload->pk_type,
+                                            ske->callbacks->context,
+                                            silc_ske_pk_verified, NULL));
+    /* NOT REACHED */
   }
 
-  /** Generate KE2 payload */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase3);
+  /** Process key material */
+  silc_fsm_next(fsm, silc_ske_st_initiator_phase4);
+  return SILC_FSM_CONTINUE;
+
+ err:
+  silc_ske_payload_ke_free(payload);
+  ske->ke2_payload = NULL;
+
+  silc_mp_uninit(ske->KEY);
+  silc_free(ske->KEY);
+  ske->KEY = NULL;
+
+  if (status == SILC_SKE_STATUS_OK)
+    return SILC_SKE_STATUS_ERROR;
+
+  /** Error */
+  ske->status = status;
+  silc_fsm_next(fsm, silc_ske_st_initiator_error);
   return SILC_FSM_CONTINUE;
 }
 
-/* Phase-3. Generate KE2 payload */
+/* Process key material */
 
-SILC_FSM_STATE(silc_ske_st_responder_phase3)
+SILC_FSM_STATE(silc_ske_st_initiator_phase4)
 {
   SilcSKE ske = fsm_context;
   SilcSKEStatus status;
-  SilcSKEKEPayload recv_payload, send_payload;
-  SilcMPInt *x, *KEY;
+  SilcSKEKEPayload payload;
+  unsigned char hash[SILC_HASH_MAXLEN];
+  SilcUInt32 hash_len;
+  SilcPublicKey public_key = NULL;
+  int key_len, block_len;
 
   if (ske->aborted) {
     /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
+    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
     return SILC_FSM_CONTINUE;
   }
 
@@ -1013,49 +1166,36 @@ SILC_FSM_STATE(silc_ske_st_responder_phase3)
     return SILC_FSM_CONTINUE;
   }
 
-  recv_payload = ske->ke1_payload;
-
-  /* The public key verification was performed only if the Mutual
-     Authentication flag is set. */
-  if (ske->start_payload &&
-      ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
-    SilcPublicKey public_key = NULL;
-    unsigned char hash[SILC_HASH_MAXLEN];
-    SilcUInt32 hash_len;
+  payload = ske->ke2_payload;
 
+  if (payload->pk_data) {
     /* Decode the public key */
-    if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
-                                    recv_payload->pk_len,
+    if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
                                     &public_key)) {
-      /** Error decoding public key */
       SILC_LOG_ERROR(("Unsupported/malformed public key received"));
-      ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
+      status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+      goto err;
     }
 
     SILC_LOG_DEBUG(("Public key is authentic"));
 
     /* Compute the hash value */
-    status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
-    if (status != SILC_SKE_STATUS_OK) {
-      /** Error computing hash */
-      ske->status = status;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
-    }
+    status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
+    if (status != SILC_SKE_STATUS_OK)
+      goto err;
 
-    SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
+    ske->hash = silc_memdup(hash, hash_len);
+    ske->hash_len = hash_len;
+
+    SILC_LOG_DEBUG(("Verifying signature (HASH)"));
 
     /* Verify signature */
     silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
-    if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
-                        recv_payload->sign_len, hash, hash_len) == FALSE) {
-      /** Incorrect signature */
+    if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
+                        payload->sign_len, hash, hash_len) == FALSE) {
       SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
-      ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
+      status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
+      goto err;
     }
 
     SILC_LOG_DEBUG(("Signature is Ok"));
@@ -1064,136 +1204,63 @@ SILC_FSM_STATE(silc_ske_st_responder_phase3)
     memset(hash, 'F', hash_len);
   }
 
-  /* Create the random number x, 1 < x < q. */
-  x = silc_calloc(1, sizeof(*x));
-  silc_mp_init(x);
-  status =
-    silc_ske_create_rnd(ske, &ske->prop->group->group_order,
-                       silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
-                       x);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error generating random number */
-    silc_mp_uninit(x);
-    silc_free(x);
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
-  }
-
-  /* Save the results for later processing */
-  send_payload = silc_calloc(1, sizeof(*send_payload));
-  ske->x = x;
-  ske->ke2_payload = send_payload;
-
-  SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
-
-  /* Do the Diffie Hellman computation, f = g ^ x mod p */
-  silc_mp_init(&send_payload->x);
-  silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
-                 &ske->prop->group->group);
-
-  SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
-
-  /* Compute the shared secret key */
-  KEY = silc_calloc(1, sizeof(*KEY));
-  silc_mp_init(KEY);
-  silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
-                 &ske->prop->group->group);
-  ske->KEY = KEY;
-
-  /** Send KE2 payload */
-  silc_fsm_next(fsm, silc_ske_st_responder_phase4);
-  return SILC_FSM_CONTINUE;
-}
-
-/* Phase-4.  Send KE2 payload */
-
-SILC_FSM_STATE(silc_ske_st_responder_phase4)
-{
-  SilcSKE ske = fsm_context;
-  SilcSKEStatus status;
-  SilcBuffer payload_buf;
-  unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1], *pk;
-  SilcUInt32 hash_len, sign_len, pk_len;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (ske->public_key && ske->private_key) {
-    SILC_LOG_DEBUG(("Getting public key"));
+  ske->status = SILC_SKE_STATUS_OK;
 
-    /* Get the public key */
-    pk = silc_pkcs_public_key_encode(ske->public_key, &pk_len);
-    if (!pk) {
-      /** Error encoding public key */
-      status = SILC_SKE_STATUS_OUT_OF_MEMORY;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
-    }
-    ske->ke2_payload->pk_data = pk;
-    ske->ke2_payload->pk_len = pk_len;
+  /* Process key material */
+  key_len = silc_cipher_get_key_len(ske->prop->cipher);
+  block_len = silc_cipher_get_key_len(ske->prop->cipher);
+  hash_len = silc_hash_len(ske->prop->hash);
+  ske->keymat = silc_ske_process_key_material(ske, block_len,
+                                             key_len, hash_len);
+  if (!ske->keymat) {
+    SILC_LOG_ERROR(("Error processing key material"));
+    status = SILC_SKE_STATUS_ERROR;
+    goto err;
+  }
 
-    SILC_LOG_DEBUG(("Computing HASH value"));
+  /* Send SUCCESS packet */
+  /* XXX */
 
-    /* Compute the hash value */
-    memset(hash, 0, sizeof(hash));
-    status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
-    if (status != SILC_SKE_STATUS_OK) {
-      /** Error computing hash */
-      ske->status = status;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
-    }
+  /** Waiting completion */
+  silc_fsm_next(fsm, silc_ske_st_initiator_end);
+  return SILC_FSM_WAIT;
 
-    ske->hash = silc_memdup(hash, hash_len);
-    ske->hash_len = hash_len;
+ err:
+  memset(hash, 'F', sizeof(hash));
+  silc_ske_payload_ke_free(payload);
+  ske->ke2_payload = NULL;
 
-    SILC_LOG_DEBUG(("Signing HASH value"));
+  silc_mp_uninit(ske->KEY);
+  silc_free(ske->KEY);
+  ske->KEY = NULL;
 
-    /* Sign the hash value */
-    silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv,
-                                  ske->private_key->prv_len);
-    if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
-       !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
-      /** Error computing signature */
-      status = SILC_SKE_STATUS_SIGNATURE_ERROR;
-      silc_fsm_next(fsm, silc_ske_st_responder_error);
-      return SILC_FSM_CONTINUE;
-    }
-    ske->ke2_payload->sign_data = silc_memdup(sign, sign_len);
-    ske->ke2_payload->sign_len = sign_len;
-    memset(sign, 0, sizeof(sign));
-  }
-  ske->ke2_payload->pk_type = ske->pk_type;
+  if (public_key)
+    silc_pkcs_public_key_free(public_key);
 
-  /* Encode the Key Exchange Payload */
-  status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
-                                     &payload_buf);
-  if (status != SILC_SKE_STATUS_OK) {
-    /** Error encoding KE payload */
-    ske->status = status;
-    silc_fsm_next(fsm, silc_ske_st_responder_error);
-    return SILC_FSM_CONTINUE;
+  if (ske->hash) {
+    memset(ske->hash, 'F', hash_len);
+    silc_free(ske->hash);
+    ske->hash = NULL;
   }
 
-  /* Send the packet. */
-  /* XXX */
-
-  silc_buffer_free(payload_buf);
+  if (status == SILC_SKE_STATUS_OK)
+    status = SILC_SKE_STATUS_ERROR;
 
-  /** Waiting completion */
-  silc_fsm_next(fsm, silc_ske_st_responder_end);
-  return SILC_FSM_WAIT;
+  /** Error */
+  ske->status = status;
+  silc_fsm_next(fsm, silc_ske_st_initiator_error);
+  return SILC_FSM_CONTINUE;
 }
 
 /* Protocol completed */
 
-SILC_FSM_STATE(silc_ske_st_responder_end)
+SILC_FSM_STATE(silc_ske_st_initiator_end)
 {
   SilcSKE ske = fsm_context;
 
   if (ske->aborted) {
     /** Aborted */
-    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
+    silc_fsm_next(fsm, silc_ske_st_initiator_aborted);
     return SILC_FSM_CONTINUE;
   }
 
@@ -1206,41 +1273,35 @@ SILC_FSM_STATE(silc_ske_st_responder_end)
 
 /* Aborted by application */
 
-SILC_FSM_STATE(silc_ske_st_responder_aborted)
+SILC_FSM_STATE(silc_ske_st_initiator_aborted)
 {
 
-  /* Send FAILURE */
-
   return SILC_FSM_FINISH;
 }
 
 /* Error occurred */
 
-SILC_FSM_STATE(silc_ske_st_responder_error)
+SILC_FSM_STATE(silc_ske_st_initiator_error)
 {
 
-  /* Send FAILURE */
-
   return SILC_FSM_FINISH;
 }
 
 
-static void silc_ske_responder_finished(SilcFSM fsm, void *fsm_context,
+static void silc_ske_initiator_finished(SilcFSM fsm, void *fsm_context,
                                        void *destructor_context)
 {
 
 }
 
-/* Starts the protocol as responder. */
+/* Starts the protocol as initiator */
 
 SilcAsyncOperation
-silc_ske_responder_start(SilcSKE ske,
-                        SilcPacketStream stream,
-                        const char *version,
-                        SilcBuffer start_payload,
-                        SilcSKESecurityPropertyFlag flags)
+silc_ske_initiator(SilcSKE ske,
+                  SilcPacketStream stream,
+                  SilcSKEStartPayload start_payload)
 {
-  SILC_LOG_DEBUG(("Start SKE as responder"));
+  SILC_LOG_DEBUG(("Start SKE as initiator"));
 
   if (!ske || !stream || !start_payload)
     return NULL;
@@ -1248,684 +1309,800 @@ silc_ske_responder_start(SilcSKE ske,
   if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
     return NULL;
 
-  if (!silc_fsm_init(&ske->fsm, ske, silc_ske_responder_finished, ske,
+  if (!silc_fsm_init(&ske->fsm, ske, silc_ske_initiator_finished, ske,
                     ske->schedule))
     return NULL;
 
-  ske->packet_buf = start_payload;
-  ske->flags = flags;
-  ske->version = strdup(version);
+  ske->start_payload = start_payload;
+
+  /* Link to packet stream to get key exchange packets */
+  ske->stream = stream;
+  silc_packet_stream_link(ske->stream, &silc_ske_stream_cbs, ske, 1000000,
+                         SILC_PACKET_KEY_EXCHANGE,
+                         SILC_PACKET_KEY_EXCHANGE_2,
+                         SILC_PACKET_SUCCESS,
+                         SILC_PACKET_FAILURE, -1);
+
+  /* Start SKE as initiator */
+  silc_fsm_start(&ske->fsm, silc_ske_st_initiator_start);
+
+  return &ske->op;
+}
+
+
+/******************************** Responder *********************************/
+
+SILC_FSM_STATE(silc_ske_st_responder_start);
+SILC_FSM_STATE(silc_ske_st_responder_phase1);
+SILC_FSM_STATE(silc_ske_st_responder_phase2);
+SILC_FSM_STATE(silc_ske_st_responder_phase3);
+SILC_FSM_STATE(silc_ske_st_responder_phase4);
+SILC_FSM_STATE(silc_ske_st_responder_phase5);
+SILC_FSM_STATE(silc_ske_st_responder_end);
+SILC_FSM_STATE(silc_ske_st_responder_aborted);
+SILC_FSM_STATE(silc_ske_st_responder_failure);
+SILC_FSM_STATE(silc_ske_st_responder_error);
+
+/* Start protocol as responder.  Wait initiator's start payload */
 
-  /* Link to packet stream to get key exchange packets */
-  ske->stream = stream;
-  silc_packet_stream_ref(ske->stream);
-  silc_packet_stream_callbacks(ske->stream, &silc_ske_stream_cbs, ske);
+SILC_FSM_STATE(silc_ske_st_responder_start)
+{
+  SilcSKE ske = fsm_context;
 
-  /* Start SKE as responder */
-  silc_fsm_start(&ske->fsm, silc_ske_st_initiator_start);
+  SILC_LOG_DEBUG(("Start"));
 
-  return &ske->op;
+  if (ske->aborted) {
+    /** Aborted */
+    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
+    return SILC_FSM_CONTINUE;
+  }
+
+  /* Start timeout */
+  /* XXX */
+
+  /** Wait for initiator */
+  silc_fsm_next(fsm, silc_ske_st_responder_phase1);
+  return SILC_FSM_WAIT;
 }
 
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_start);
+/* Decode initiator's start payload */
 
-SILC_FSM_STATE(silc_ske_st_rekey_initiator_start)
+SILC_FSM_STATE(silc_ske_st_responder_phase1)
 {
+  SilcSKE ske = fsm_context;
+  SilcSKEStatus status;
+  SilcSKEStartPayload remote_payload = NULL, payload = NULL;
+  SilcBuffer packet_buf = &ske->packet->buffer;
 
-}
+  SILC_LOG_DEBUG(("Start"));
 
-/* Starts rekey protocol as initiator */
+  if (ske->aborted) {
+    /** Aborted */
+    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
+    return SILC_FSM_CONTINUE;
+  }
 
-SilcAsyncOperation
-silc_ske_rekey_initiator_start(SilcSKE ske,
-                              SilcPacketStream stream,
-                              SilcSKERekeyMaterial rekey)
-{
-  SILC_LOG_DEBUG(("Start SKE rekey as initator"));
+  /* See if received failure from remote */
+  if (ske->packet->type == SILC_PACKET_FAILURE) {
+    silc_fsm_next(fsm, silc_ske_st_responder_failure);
+    return SILC_FSM_CONTINUE;
+  }
 
-  if (!ske || !stream || !rekey)
-    return NULL;
+  /* Decode the payload */
+  status = silc_ske_payload_start_decode(ske, packet_buf, &remote_payload);
+  if (status != SILC_SKE_STATUS_OK) {
+    /** Error decoding Start Payload */
+    silc_packet_free(ske->packet);
+    ske->status = status;
+    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
-    return NULL;
+  /* Take a copy of the payload buffer for future use. It is used to
+     compute the HASH value. */
+  ske->start_payload_copy = silc_buffer_copy(packet_buf);
 
-  if (!silc_fsm_init(&ske->fsm, ske, NULL, NULL, ske->schedule))
-    return NULL;
+  silc_packet_free(ske->packet);
 
-  ske->rekey = rekey;
+  /* Force the mutual authentication flag if we want to do it. */
+  if (ske->flags & SILC_SKE_SP_FLAG_MUTUAL) {
+    SILC_LOG_DEBUG(("Force mutual authentication"));
+    remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
+  }
 
-  /* Link to packet stream to get key exchange packets */
-  ske->stream = stream;
-  silc_packet_stream_ref(ske->stream);
-  silc_packet_stream_callbacks(ske->stream, &silc_ske_stream_cbs, ske);
+  /* Force PFS flag if we require it */
+  if (ske->flags & SILC_SKE_SP_FLAG_PFS) {
+    SILC_LOG_DEBUG(("Force PFS"));
+    remote_payload->flags |= SILC_SKE_SP_FLAG_PFS;
+  }
 
-  /* Start SKE rekey as initiator */
-  silc_fsm_start(&ske->fsm, silc_ske_st_rekey_initiator_start);
+  /* Disable IV Included flag if requested */
+  if (remote_payload->flags & SILC_SKE_SP_FLAG_IV_INCLUDED &&
+      !(ske->flags & SILC_SKE_SP_FLAG_IV_INCLUDED)) {
+    SILC_LOG_DEBUG(("We do not support IV Included flag"));
+    remote_payload->flags &= ~SILC_SKE_SP_FLAG_IV_INCLUDED;
+  }
 
-  return &ske->op;
-}
+  /* Parse and select the security properties from the payload */
+  payload = silc_calloc(1, sizeof(*payload));
+  status = silc_ske_select_security_properties(ske, payload, remote_payload);
+  if (status != SILC_SKE_STATUS_OK) {
+    /** Error selecting proposal */
+    if (remote_payload)
+      silc_ske_payload_start_free(remote_payload);
+    silc_free(payload);
+    ske->status = status;
+    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-SILC_FSM_STATE(silc_ske_st_rekey_responder_start);
+  ske->start_payload = payload;
 
-SILC_FSM_STATE(silc_ske_st_rekey_responder_start)
-{
+  silc_ske_payload_start_free(remote_payload);
 
+  /** Send proposal to initiator */
+  silc_fsm_next(fsm, silc_ske_st_responder_phase2);
+  return SILC_FSM_CONTINUE;
 }
 
-/* Starts rekey protocol as responder */
+/* Phase-2.  Send Start Payload */
 
-SilcAsyncOperation
-silc_ske_rekey_responder_start(SilcSKE ske,
-                              SilcPacketStream stream,
-                              SilcBuffer ke_payload,
-                              SilcSKERekeyMaterial rekey)
+SILC_FSM_STATE(silc_ske_st_responder_phase2)
 {
-  SILC_LOG_DEBUG(("Start SKE rekey as responder"));
+  SilcSKE ske = fsm_context;
+  SilcSKEStatus status;
+  SilcBuffer payload_buf;
+  SilcSKESecurityProperties prop;
+  SilcSKEDiffieHellmanGroup group = NULL;
 
-  if (!ske || !stream || !rekey)
-    return NULL;
-  if (rekey->pfs && !ke_payload)
-    return NULL;
+  SILC_LOG_DEBUG(("Start"));
 
-  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
-    return NULL;
+  /* Allocate security properties from the payload. These are allocated
+     only for this negotiation and will be free'd after KE is over. */
+  ske->prop = prop = silc_calloc(1, sizeof(*prop));
+  if (!ske->prop) {
+    status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+    goto err;
+  }
+  prop->flags = ske->start_payload->flags;
+  status = silc_ske_group_get_by_name(ske->start_payload->ke_grp_list,
+                                     &group);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
 
-  if (!silc_fsm_init(&ske->fsm, ske, NULL, NULL, ske->schedule))
-    return NULL;
+  prop->group = group;
 
-  ske->packet_buf = ke_payload;
-  ske->rekey = rekey;
+  /* XXX these shouldn't be allocated before we know the remote's
+     public key type.  It's unnecessary to allocate these because the
+     select_security_properties has succeeded already. */
+  if (silc_pkcs_alloc(ske->start_payload->pkcs_alg_list,
+                     SILC_PKCS_SILC, &prop->pkcs) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_PKCS;
+    goto err;
+  }
+  if (silc_cipher_alloc(ske->start_payload->enc_alg_list,
+                       &prop->cipher) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
+    goto err;
+  }
+  if (silc_hash_alloc(ske->start_payload->hash_alg_list,
+                     &prop->hash) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
+    goto err;
+  }
+  if (silc_hmac_alloc(ske->start_payload->hmac_alg_list, NULL,
+                     &prop->hmac) == FALSE) {
+    status = SILC_SKE_STATUS_UNKNOWN_HMAC;
+    goto err;
+  }
 
-  /* Link to packet stream to get key exchange packets */
-  ske->stream = stream;
-  silc_packet_stream_ref(ske->stream);
-  silc_packet_stream_callbacks(ske->stream, &silc_ske_stream_cbs, ske);
+  /* Encode the payload */
+  status = silc_ske_payload_start_encode(ske, ske->start_payload,
+                                        &payload_buf);
+  if (status != SILC_SKE_STATUS_OK)
+    goto err;
 
-  /* Start SKE rekey as responder */
-  silc_fsm_start(&ske->fsm, silc_ske_st_rekey_responder_start);
+  /* Send the packet. */
+  if (!silc_packet_send(ske->stream, SILC_PACKET_KEY_EXCHANGE, 0,
+                       payload_buf->data, silc_buffer_len(payload_buf)))
+    goto err;
 
-  return &ske->op;
-}
+  silc_buffer_free(payload_buf);
 
-/* Assembles security properties */
+  /** Waiting initiator's KE payload */
+  silc_fsm_next(fsm, silc_ske_st_responder_phase3);
+  return SILC_FSM_WAIT;
 
-SilcSKEStartPayload
-silc_ske_assemble_security_properties(SilcSKE ske,
-                                     SilcSKESecurityPropertyFlag flags,
-                                     const char *version)
-{
-  SilcSKEStartPayload rp;
-  int i;
+ err:
+  if (group)
+    silc_ske_group_free(group);
 
-  SILC_LOG_DEBUG(("Assembling KE Start Payload"));
+  if (prop->pkcs)
+    silc_pkcs_free(prop->pkcs);
+  if (prop->cipher)
+    silc_cipher_free(prop->cipher);
+  if (prop->hash)
+    silc_hash_free(prop->hash);
+  if (prop->hmac)
+    silc_hmac_free(prop->hmac);
+  silc_free(prop);
+  ske->prop = NULL;
 
-  rp = silc_calloc(1, sizeof(*rp));
+  if (status == SILC_SKE_STATUS_OK)
+    status = SILC_SKE_STATUS_ERROR;
 
-  /* Set flags */
-  rp->flags = (unsigned char)flags;
+  /** Error */
+  ske->status = status;
+  silc_fsm_next(fsm, silc_ske_st_responder_error);
+  return SILC_FSM_CONTINUE;
+}
 
-  /* Set random cookie */
-  rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
-  for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
-    rp->cookie[i] = silc_rng_get_byte_fast(ske->rng);
-  rp->cookie_len = SILC_SKE_COOKIE_LEN;
+/* Phase-3.  Decode initiator's KE payload */
 
-  /* Put version */
-  rp->version = strdup(version);
-  rp->version_len = strlen(version);
+SILC_FSM_STATE(silc_ske_st_responder_phase3)
+{
+  SilcSKE ske = fsm_context;
+  SilcSKEStatus status;
+  SilcSKEKEPayload recv_payload;
+  SilcBuffer packet_buf = &ske->packet->buffer;
 
-  /* Get supported Key Exhange groups */
-  rp->ke_grp_list = silc_ske_get_supported_groups();
-  rp->ke_grp_len = strlen(rp->ke_grp_list);
+  SILC_LOG_DEBUG(("Start"));
 
-  /* Get supported PKCS algorithms */
-  rp->pkcs_alg_list = silc_pkcs_get_supported();
-  rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
+  if (ske->aborted) {
+    /** Aborted */
+    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
+    return SILC_FSM_CONTINUE;
+  }
 
-  /* Get supported encryption algorithms */
-  rp->enc_alg_list = silc_cipher_get_supported();
-  rp->enc_alg_len = strlen(rp->enc_alg_list);
+  /* See if received failure from remote */
+  if (ske->packet->type == SILC_PACKET_FAILURE) {
+    silc_fsm_next(fsm, silc_ske_st_responder_failure);
+    return SILC_FSM_CONTINUE;
+  }
 
-  /* Get supported hash algorithms */
-  rp->hash_alg_list = silc_hash_get_supported();
-  rp->hash_alg_len = strlen(rp->hash_alg_list);
+  /* Decode Key Exchange Payload */
+  status = silc_ske_payload_ke_decode(ske, packet_buf, &recv_payload);
+  if (status != SILC_SKE_STATUS_OK) {
+    /** Error decoding KE payload */
+    silc_packet_free(ske->packet);
+    ske->status = status;
+    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-  /* Get supported HMACs */
-  rp->hmac_alg_list = silc_hmac_get_supported();
-  rp->hmac_alg_len = strlen(rp->hmac_alg_list);
+  ske->ke1_payload = recv_payload;
 
-  /* XXX */
-  /* Get supported compression algorithms */
-  rp->comp_alg_list = strdup("none");
-  rp->comp_alg_len = strlen("none");
+  silc_packet_free(ske->packet);
+
+  /* Verify the received public key and verify the signature if we are
+     doing mutual authentication. */
+  if (ske->start_payload &&
+      ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
+
+    SILC_LOG_DEBUG(("We are doing mutual authentication"));
+
+    if (!recv_payload->pk_data && ske->callbacks->verify_key) {
+      /** Public key not provided */
+      SILC_LOG_ERROR(("Remote end did not send its public key (or "
+                     "certificate), even though we require it"));
+      ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
+      silc_fsm_next(fsm, silc_ske_st_responder_error);
+      return SILC_FSM_CONTINUE;
+    }
 
-  rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
-    2 + rp->version_len +
-    2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
-    2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
-    2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
+    if (recv_payload->pk_data && ske->callbacks->verify_key) {
+      SILC_LOG_DEBUG(("Verifying public key"));
 
-  return rp;
+      /** Waiting public key verification */
+      silc_fsm_next(fsm, silc_ske_st_responder_phase4);
+      SILC_FSM_CALL(ske->callbacks->verify_key(ske, recv_payload->pk_data,
+                                              recv_payload->pk_len,
+                                              recv_payload->pk_type,
+                                              ske->callbacks->context,
+                                              silc_ske_pk_verified, NULL));
+      /* NOT REACHED */
+    }
+  }
+
+  /** Generate KE2 payload */
+  silc_fsm_next(fsm, silc_ske_st_responder_phase4);
+  return SILC_FSM_CONTINUE;
 }
 
-/* Selects the supported security properties from the remote end's Key
-   Exchange Start Payload. */
+/* Phase-4. Generate KE2 payload */
 
-static SilcSKEStatus
-silc_ske_select_security_properties(SilcSKE ske,
-                                   const char *version,
-                                   SilcSKEStartPayload payload,
-                                   SilcSKEStartPayload remote_payload)
+SILC_FSM_STATE(silc_ske_st_responder_phase4)
 {
+  SilcSKE ske = fsm_context;
   SilcSKEStatus status;
-  SilcSKEStartPayload rp;
-  char *cp;
-  int len;
+  SilcSKEKEPayload recv_payload, send_payload;
+  SilcMPInt *x, *KEY;
 
-  SILC_LOG_DEBUG(("Parsing KE Start Payload"));
+  if (ske->aborted) {
+    /** Aborted */
+    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
+    return SILC_FSM_CONTINUE;
+  }
 
-  rp = remote_payload;
+  /* Check result of public key verification */
+  if (ske->status != SILC_SKE_STATUS_OK) {
+    /** Public key not verified */
+    SILC_LOG_DEBUG(("Public key verification failed"));
+    silc_fsm_next(fsm, silc_ske_st_initiator_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-  /* Check version string */
-  if (ske->callbacks->check_version) {
-    status = ske->callbacks->check_version(ske, rp->version,
-                                          rp->version_len,
-                                          ske->callbacks->context);
+  recv_payload = ske->ke1_payload;
+
+  /* The public key verification was performed only if the Mutual
+     Authentication flag is set. */
+  if (ske->start_payload &&
+      ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
+    SilcPublicKey public_key = NULL;
+    unsigned char hash[SILC_HASH_MAXLEN];
+    SilcUInt32 hash_len;
+
+    /* Decode the public key */
+    if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
+                                    recv_payload->pk_len,
+                                    &public_key)) {
+      /** Error decoding public key */
+      SILC_LOG_ERROR(("Unsupported/malformed public key received"));
+      ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+      silc_fsm_next(fsm, silc_ske_st_responder_error);
+      return SILC_FSM_CONTINUE;
+    }
+
+    SILC_LOG_DEBUG(("Public key is authentic"));
+
+    /* Compute the hash value */
+    status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
     if (status != SILC_SKE_STATUS_OK) {
+      /** Error computing hash */
       ske->status = status;
-      return status;
+      silc_fsm_next(fsm, silc_ske_st_responder_error);
+      return SILC_FSM_CONTINUE;
     }
-  }
 
-  ske->remote_version = silc_memdup(rp->version, rp->version_len);
+    SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
 
-  /* Flags are returned unchanged. */
-  payload->flags = rp->flags;
+    /* Verify signature */
+    silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
+    if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
+                        recv_payload->sign_len, hash, hash_len) == FALSE) {
+      /** Incorrect signature */
+      SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
+      ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
+      silc_fsm_next(fsm, silc_ske_st_responder_error);
+      return SILC_FSM_CONTINUE;
+    }
 
-  /* Take cookie, we must return it to sender unmodified. */
-  payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
-  payload->cookie_len = SILC_SKE_COOKIE_LEN;
-  memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
+    SILC_LOG_DEBUG(("Signature is Ok"));
 
-  /* Put our version to our reply */
-  payload->version = strdup(version);
-  payload->version_len = strlen(version);
+    silc_pkcs_public_key_free(public_key);
+    memset(hash, 'F', hash_len);
+  }
 
-  /* Get supported Key Exchange groups */
-  cp = rp->ke_grp_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
+  /* Create the random number x, 1 < x < q. */
+  x = silc_calloc(1, sizeof(*x));
+  silc_mp_init(x);
+  status =
+    silc_ske_create_rnd(ske, &ske->prop->group->group_order,
+                       silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
+                       x);
+  if (status != SILC_SKE_STATUS_OK) {
+    /** Error generating random number */
+    silc_mp_uninit(x);
+    silc_free(x);
+    ske->status = status;
+    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      memcpy(item, cp, len);
+  /* Save the results for later processing */
+  send_payload = silc_calloc(1, sizeof(*send_payload));
+  ske->x = x;
+  ske->ke2_payload = send_payload;
 
-      SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
+  SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
 
-      if (silc_ske_group_get_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
-       SILC_LOG_DEBUG(("Found KE group `%s'", item));
+  /* Do the Diffie Hellman computation, f = g ^ x mod p */
+  silc_mp_init(&send_payload->x);
+  silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
+                 &ske->prop->group->group);
 
-       payload->ke_grp_len = len;
-       payload->ke_grp_list = item;
-       break;
-      }
+  SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
 
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
+  /* Compute the shared secret key */
+  KEY = silc_calloc(1, sizeof(*KEY));
+  silc_mp_init(KEY);
+  silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
+                 &ske->prop->group->group);
+  ske->KEY = KEY;
 
-      if (item)
-       silc_free(item);
-    }
+  /** Send KE2 payload */
+  silc_fsm_next(fsm, silc_ske_st_responder_phase5);
+  return SILC_FSM_CONTINUE;
+}
 
-    if (!payload->ke_grp_len && !payload->ke_grp_list) {
-      SILC_LOG_DEBUG(("Could not find supported KE group"));
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_GROUP;
-    }
-  } else {
+/* Phase-5.  Send KE2 payload */
 
-    if (!rp->ke_grp_len) {
-      SILC_LOG_DEBUG(("KE group not defined in payload"));
-      silc_free(payload);
-      return SILC_SKE_STATUS_BAD_PAYLOAD;
+SILC_FSM_STATE(silc_ske_st_responder_phase5)
+{
+  SilcSKE ske = fsm_context;
+  SilcSKEStatus status;
+  SilcBuffer payload_buf;
+  unsigned char hash[SILC_HASH_MAXLEN], sign[2048 + 1], *pk;
+  SilcUInt32 hash_len, sign_len, pk_len;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (ske->public_key && ske->private_key) {
+    SILC_LOG_DEBUG(("Getting public key"));
+
+    /* Get the public key */
+    pk = silc_pkcs_public_key_encode(ske->public_key, &pk_len);
+    if (!pk) {
+      /** Error encoding public key */
+      status = SILC_SKE_STATUS_OUT_OF_MEMORY;
+      silc_fsm_next(fsm, silc_ske_st_responder_error);
+      return SILC_FSM_CONTINUE;
     }
+    ske->ke2_payload->pk_data = pk;
+    ske->ke2_payload->pk_len = pk_len;
 
-    SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
-    SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
+    SILC_LOG_DEBUG(("Computing HASH value"));
 
-    payload->ke_grp_len = rp->ke_grp_len;
-    payload->ke_grp_list = strdup(rp->ke_grp_list);
-  }
+    /* Compute the hash value */
+    memset(hash, 0, sizeof(hash));
+    status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
+    if (status != SILC_SKE_STATUS_OK) {
+      /** Error computing hash */
+      ske->status = status;
+      silc_fsm_next(fsm, silc_ske_st_responder_error);
+      return SILC_FSM_CONTINUE;
+    }
 
-  /* Get supported PKCS algorithms */
-  cp = rp->pkcs_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
+    ske->hash = silc_memdup(hash, hash_len);
+    ske->hash_len = hash_len;
 
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      memcpy(item, cp, len);
+    SILC_LOG_DEBUG(("Signing HASH value"));
 
-      SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
+    /* Sign the hash value */
+    silc_pkcs_private_key_data_set(ske->prop->pkcs, ske->private_key->prv,
+                                  ske->private_key->prv_len);
+    if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
+       !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
+      /** Error computing signature */
+      status = SILC_SKE_STATUS_SIGNATURE_ERROR;
+      silc_fsm_next(fsm, silc_ske_st_responder_error);
+      return SILC_FSM_CONTINUE;
+    }
+    ske->ke2_payload->sign_data = silc_memdup(sign, sign_len);
+    ske->ke2_payload->sign_len = sign_len;
+    memset(sign, 0, sizeof(sign));
+  }
+  ske->ke2_payload->pk_type = ske->pk_type;
 
-      if (silc_pkcs_is_supported(item) == TRUE) {
-       SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
+  /* Encode the Key Exchange Payload */
+  status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
+                                     &payload_buf);
+  if (status != SILC_SKE_STATUS_OK) {
+    /** Error encoding KE payload */
+    ske->status = status;
+    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-       payload->pkcs_alg_len = len;
-       payload->pkcs_alg_list = item;
-       break;
-      }
+  /* Send the packet. */
+  if (!silc_packet_send(ske->stream, SILC_PACKET_KEY_EXCHANGE_2, 0,
+                       payload_buf->data, silc_buffer_len(payload_buf))) {
+    ske->status = SILC_SKE_STATUS_ERROR;
+    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
+  silc_buffer_free(payload_buf);
 
-      if (item)
-       silc_free(item);
-    }
+  /** Waiting completion */
+  silc_fsm_next(fsm, silc_ske_st_responder_end);
+  return SILC_FSM_WAIT;
+}
 
-    if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
-      SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_PKCS;
-    }
-  } else {
+/* Protocol completed */
 
-    if (!rp->pkcs_alg_len) {
-      SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_BAD_PAYLOAD;
-    }
+SILC_FSM_STATE(silc_ske_st_responder_end)
+{
+  SilcSKE ske = fsm_context;
+  unsigned char tmp[4];
+  SilcUInt32 hash_len, key_len, block_len;
 
-    SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
-    SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
+  if (ske->aborted) {
+    /** Aborted */
+    silc_fsm_next(fsm, silc_ske_st_responder_aborted);
+    return SILC_FSM_CONTINUE;
+  }
 
-    payload->pkcs_alg_len = rp->pkcs_alg_len;
-    payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
+  /* Check the result of the protocol */
+  if (ske->packet->type == SILC_PACKET_FAILURE) {
+    silc_fsm_next(fsm, silc_ske_st_responder_failure);
+    return SILC_FSM_CONTINUE;
   }
+  silc_packet_free(ske->packet);
 
-  /* Get supported encryption algorithms */
-  cp = rp->enc_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
+  /* Process key material */
+  key_len = silc_cipher_get_key_len(ske->prop->cipher);
+  block_len = silc_cipher_get_key_len(ske->prop->cipher);
+  hash_len = silc_hash_len(ske->prop->hash);
+  ske->keymat = silc_ske_process_key_material(ske, block_len,
+                                             key_len, hash_len);
+  if (!ske->keymat) {
+    /** Error processing key material */
+    ske->status = SILC_SKE_STATUS_ERROR;
+    silc_fsm_next(fsm, silc_ske_st_responder_error);
+    return SILC_FSM_CONTINUE;
+  }
 
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      memcpy(item, cp, len);
+  /* Send SUCCESS packet */
+  SILC_PUT32_MSB(SILC_SKE_STATUS_OK, tmp);
+  silc_packet_send(ske->stream, SILC_PACKET_SUCCESS, 0, tmp, 4);
 
-      SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
+  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
 
-      if (silc_cipher_is_supported(item) == TRUE) {
-       SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
+  /* Call the completion callback */
+  if (ske->callbacks->completed)
+    ske->callbacks->completed(ske, ske->status, ske->prop, ske->keymat,
+                             ske->rekey, ske->callbacks->context);
 
-       payload->enc_alg_len = len;
-       payload->enc_alg_list = item;
-       break;
-      }
+  return SILC_FSM_FINISH;
+}
 
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
+/* Aborted by application */
 
-      if (item)
-       silc_free(item);
-    }
+SILC_FSM_STATE(silc_ske_st_responder_aborted)
+{
+  SilcSKE ske = fsm_context;
+  unsigned char tmp[4];
 
-    if (!payload->enc_alg_len && !payload->enc_alg_list) {
-      SILC_LOG_DEBUG(("Could not find supported encryption alg"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_CIPHER;
-    }
-  } else {
+  SILC_LOG_DEBUG(("Key exchange protocol aborted"));
 
-    if (!rp->enc_alg_len) {
-      SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_BAD_PAYLOAD;
-    }
+  /* Send FAILURE packet */
+  SILC_PUT32_MSB(SILC_SKE_STATUS_ERROR, tmp);
+  silc_packet_send(ske->stream, SILC_PACKET_FAILURE, 0, tmp, 4);
 
-    SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
-                   rp->enc_alg_list));
+  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
 
-    payload->enc_alg_len = rp->enc_alg_len;
-    payload->enc_alg_list = strdup(rp->enc_alg_list);
-  }
+  return SILC_FSM_FINISH;
+}
 
-  /* Get supported hash algorithms */
-  cp = rp->hash_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
+/* Failure received from remote */
 
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      memcpy(item, cp, len);
+SILC_FSM_STATE(silc_ske_st_responder_failure)
+{
+  SilcSKE ske = fsm_context;
+  SilcUInt32 error = SILC_SKE_STATUS_ERROR;
 
-      SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
+  SILC_LOG_DEBUG(("Key exchange protocol failed"));
 
-      if (silc_hash_is_supported(item) == TRUE) {
-       SILC_LOG_DEBUG(("Found hash alg `%s'", item));
+  if (silc_buffer_len(&ske->packet->buffer) == 4)
+    SILC_GET32_MSB(error, ske->packet->buffer.data);
+  ske->status = error;
 
-       payload->hash_alg_len = len;
-       payload->hash_alg_list = item;
-       break;
-      }
+  /* Call the completion callback */
+  if (ske->callbacks->completed)
+    ske->callbacks->completed(ske, ske->status, NULL, NULL, NULL,
+                             ske->callbacks->context);
 
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
+  silc_packet_free(ske->packet);
+  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
 
-      if (item)
-       silc_free(item);
-    }
+  return SILC_FSM_FINISH;
+}
 
-    if (!payload->hash_alg_len && !payload->hash_alg_list) {
-      SILC_LOG_DEBUG(("Could not find supported hash alg"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload->enc_alg_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
-    }
-  } else {
+/* Error occurred */
 
-    if (!rp->hash_alg_len) {
-      SILC_LOG_DEBUG(("Hash alg not defined in payload"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload->enc_alg_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_BAD_PAYLOAD;
-    }
+SILC_FSM_STATE(silc_ske_st_responder_error)
+{
+  SilcSKE ske = fsm_context;
+  unsigned char tmp[4];
 
-    SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
-                   rp->hash_alg_list));
+  SILC_LOG_DEBUG(("Error %d (%s) during key exchange protocol",
+                 ske->status, silc_ske_map_status(ske->status)));
 
-    payload->hash_alg_len = rp->hash_alg_len;
-    payload->hash_alg_list = strdup(rp->hash_alg_list);
-  }
+  /* Send FAILURE packet */
+  if (ske->status > SILC_SKE_STATUS_INVALID_COOKIE)
+    ske->status = SILC_SKE_STATUS_BAD_PAYLOAD;
+  SILC_PUT32_MSB(ske->status, tmp);
+  silc_packet_send(ske->stream, SILC_PACKET_FAILURE, 0, tmp, 4);
 
-  /* Get supported HMACs */
-  cp = rp->hmac_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
+  silc_packet_stream_unlink(ske->stream, &silc_ske_stream_cbs, ske);
 
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      memcpy(item, cp, len);
+  return SILC_FSM_FINISH;
+}
 
-      SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
 
-      if (silc_hmac_is_supported(item) == TRUE) {
-       SILC_LOG_DEBUG(("Found HMAC `%s'", item));
+static void silc_ske_responder_finished(SilcFSM fsm, void *fsm_context,
+                                       void *destructor_context)
+{
 
-       payload->hmac_alg_len = len;
-       payload->hmac_alg_list = item;
-       break;
-      }
+}
 
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
+/* Starts the protocol as responder. */
 
-      if (item)
-       silc_free(item);
-    }
+SilcAsyncOperation
+silc_ske_responder(SilcSKE ske,
+                  SilcPacketStream stream,
+                  const char *version,
+                  SilcSKESecurityPropertyFlag flags)
+{
+  SILC_LOG_DEBUG(("Start SKE as responder"));
 
-    if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
-      SILC_LOG_DEBUG(("Could not find supported HMAC"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload->enc_alg_list);
-      silc_free(payload->hash_alg_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_UNKNOWN_HMAC;
-    }
-  } else {
+  if (!ske || !stream || !version) {
+    return NULL;
+  }
 
-    if (!rp->hmac_alg_len) {
-      SILC_LOG_DEBUG(("HMAC not defined in payload"));
-      silc_free(payload->ke_grp_list);
-      silc_free(payload->pkcs_alg_list);
-      silc_free(payload->enc_alg_list);
-      silc_free(payload->hash_alg_list);
-      silc_free(payload);
-      return SILC_SKE_STATUS_BAD_PAYLOAD;
-    }
+  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
+    return NULL;
 
-    SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
-                   rp->hmac_alg_list));
+  if (!silc_fsm_init(&ske->fsm, ske, silc_ske_responder_finished, ske,
+                    ske->schedule))
+    return NULL;
 
-    payload->hmac_alg_len = rp->hmac_alg_len;
-    payload->hmac_alg_list = strdup(rp->hmac_alg_list);
-  }
+  ske->flags = flags;
+  ske->version = strdup(version);
+  if (!ske->version)
+    return NULL;
+  ske->responder = TRUE;
 
-  /* Get supported compression algorithms */
-  cp = rp->comp_alg_list;
-  if (cp && strchr(cp, ',')) {
-    while(cp) {
-      char *item;
+  /* Link to packet stream to get key exchange packets */
+  ske->stream = stream;
+  silc_packet_stream_link(ske->stream, &silc_ske_stream_cbs, ske, 1000000,
+                         SILC_PACKET_KEY_EXCHANGE,
+                         SILC_PACKET_KEY_EXCHANGE_1,
+                         SILC_PACKET_SUCCESS,
+                         SILC_PACKET_FAILURE, -1);
 
-      len = strcspn(cp, ",");
-      item = silc_calloc(len + 1, sizeof(char));
-      memcpy(item, cp, len);
+  /* Start SKE as responder */
+  silc_fsm_start(&ske->fsm, silc_ske_st_responder_start);
 
-      SILC_LOG_DEBUG(("Proposed Compression `%s'", item));
+  return &ske->op;
+}
 
-#if 1
-      if (!strcmp(item, "none")) {
-       SILC_LOG_DEBUG(("Found Compression `%s'", item));
-       payload->comp_alg_len = len;
-       payload->comp_alg_list = item;
-       break;
-      }
-#else
-      if (silc_hmac_is_supported(item) == TRUE) {
-       SILC_LOG_DEBUG(("Found Compression `%s'", item));
-       payload->comp_alg_len = len;
-       payload->comp_alg_list = item;
-       break;
-      }
-#endif
+SILC_FSM_STATE(silc_ske_st_rekey_initiator_start);
+
+SILC_FSM_STATE(silc_ske_st_rekey_initiator_start)
+{
+  return SILC_FSM_FINISH;
+}
+
+/* Starts rekey protocol as initiator */
 
-      cp += len;
-      if (strlen(cp) == 0)
-       cp = NULL;
-      else
-       cp++;
+SilcAsyncOperation
+silc_ske_rekey_initiator(SilcSKE ske,
+                        SilcPacketStream stream,
+                        SilcSKERekeyMaterial rekey)
+{
+  SILC_LOG_DEBUG(("Start SKE rekey as initator"));
 
-      if (item)
-       silc_free(item);
-    }
-  }
+  if (!ske || !stream || !rekey)
+    return NULL;
 
-  payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
-    2 + payload->version_len +
-    2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
-    2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
-    2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
+  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
+    return NULL;
 
-  return SILC_SKE_STATUS_OK;
+  if (!silc_fsm_init(&ske->fsm, ske, NULL, NULL, ske->schedule))
+    return NULL;
+
+  ske->rekey = rekey;
+
+  /* Link to packet stream to get key exchange packets */
+  ske->stream = stream;
+
+  /* Start SKE rekey as initiator */
+  silc_fsm_start(&ske->fsm, silc_ske_st_rekey_initiator_start);
+
+  return &ske->op;
 }
 
-/* Creates random number such that 1 < rnd < n and at most length
-   of len bits. The rnd sent as argument must be initialized. */
+SILC_FSM_STATE(silc_ske_st_rekey_responder_start);
 
-static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
-                                        SilcUInt32 len,
-                                        SilcMPInt *rnd)
+SILC_FSM_STATE(silc_ske_st_rekey_responder_start)
 {
-  SilcSKEStatus status = SILC_SKE_STATUS_OK;
-  unsigned char *string;
-  SilcUInt32 l;
+  return SILC_FSM_FINISH;
+}
 
-  if (!len)
-    return SILC_SKE_STATUS_ERROR;
+/* Starts rekey protocol as responder */
 
-  SILC_LOG_DEBUG(("Creating random number"));
+SilcAsyncOperation
+silc_ske_rekey_responder(SilcSKE ske,
+                        SilcPacketStream stream,
+                        SilcBuffer ke_payload,
+                        SilcSKERekeyMaterial rekey)
+{
+  SILC_LOG_DEBUG(("Start SKE rekey as responder"));
 
-  l = ((len - 1) / 8);
+  if (!ske || !stream || !rekey)
+    return NULL;
+  if (rekey->pfs && !ke_payload)
+    return NULL;
 
-  /* Get the random number as string */
-  string = silc_rng_get_rn_data(ske->rng, l);
-  if (!string)
-    return SILC_SKE_STATUS_OUT_OF_MEMORY;
+  if (!silc_async_init(&ske->op, silc_ske_abort, NULL, ske))
+    return NULL;
 
-  /* Decode the string into a MP integer */
-  silc_mp_bin2mp(string, l, rnd);
-  silc_mp_mod_2exp(rnd, rnd, len);
+  if (!silc_fsm_init(&ske->fsm, ske, NULL, NULL, ske->schedule))
+    return NULL;
 
-  /* Checks */
-  if (silc_mp_cmp_ui(rnd, 1) < 0)
-    status = SILC_SKE_STATUS_ERROR;
-  if (silc_mp_cmp(rnd, n) >= 0)
-    status = SILC_SKE_STATUS_ERROR;
+  //  ske->packet_buf = ke_payload;
+  ske->rekey = rekey;
 
-  memset(string, 'F', l);
-  silc_free(string);
+  /* Link to packet stream to get key exchange packets */
+  ske->stream = stream;
 
-  return status;
+  /* Start SKE rekey as responder */
+  silc_fsm_start(&ske->fsm, silc_ske_st_rekey_responder_start);
+
+  return &ske->op;
 }
 
-/* Creates a hash value HASH as defined in the SKE protocol. If the
-   `initiator' is TRUE then this function is used to create the HASH_i
-   hash value defined in the protocol. If it is FALSE then this is used
-   to create the HASH value defined by the protocol. */
+/* Assembles security properties */
 
-static SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
-                                       unsigned char *return_hash,
-                                       SilcUInt32 *return_hash_len,
-                                       int initiator)
+SilcSKEStartPayload
+silc_ske_assemble_security_properties(SilcSKE ske,
+                                     SilcSKESecurityPropertyFlag flags,
+                                     const char *version)
 {
-  SilcSKEStatus status = SILC_SKE_STATUS_OK;
-  SilcBuffer buf;
-  unsigned char *e, *f, *KEY;
-  SilcUInt32 e_len, f_len, KEY_len;
-  int ret;
+  SilcSKEStartPayload rp;
+  int i;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Assembling KE Start Payload"));
 
-  if (initiator == FALSE) {
-    e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
-    f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
-    KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
+  rp = silc_calloc(1, sizeof(*rp));
 
-    /* Format the buffer used to compute the hash value */
-    buf = silc_buffer_alloc_size(silc_buffer_len(ske->start_payload_copy) +
-                                ske->ke2_payload->pk_len +
-                                ske->ke1_payload->pk_len +
-                                e_len + f_len + KEY_len);
-    if (!buf)
-      return SILC_SKE_STATUS_OUT_OF_MEMORY;
+  /* Set flags */
+  rp->flags = (unsigned char)flags;
 
-    /* Initiator is not required to send its public key */
-    if (!ske->ke1_payload->pk_data) {
-      ret =
-       silc_buffer_format(buf,
-                          SILC_STR_UI_XNSTRING(
-                                  ske->start_payload_copy->data,
-                                  silc_buffer_len(ske->start_payload_copy)),
-                          SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
-                                               ske->ke2_payload->pk_len),
-                          SILC_STR_UI_XNSTRING(e, e_len),
-                          SILC_STR_UI_XNSTRING(f, f_len),
-                          SILC_STR_UI_XNSTRING(KEY, KEY_len),
-                          SILC_STR_END);
-    } else {
-      ret =
-       silc_buffer_format(buf,
-                          SILC_STR_UI_XNSTRING(
-                                  ske->start_payload_copy->data,
-                                  silc_buffer_len(ske->start_payload_copy)),
-                          SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
-                                               ske->ke2_payload->pk_len),
-                          SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
-                                               ske->ke1_payload->pk_len),
-                          SILC_STR_UI_XNSTRING(e, e_len),
-                          SILC_STR_UI_XNSTRING(f, f_len),
-                          SILC_STR_UI_XNSTRING(KEY, KEY_len),
-                          SILC_STR_END);
-    }
-    if (ret == -1) {
-      silc_buffer_free(buf);
-      memset(e, 0, e_len);
-      memset(f, 0, f_len);
-      memset(KEY, 0, KEY_len);
-      silc_free(e);
-      silc_free(f);
-      silc_free(KEY);
-      return SILC_SKE_STATUS_ERROR;
-    }
+  /* Set random cookie */
+  rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
+  for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
+    rp->cookie[i] = silc_rng_get_byte_fast(ske->rng);
+  rp->cookie_len = SILC_SKE_COOKIE_LEN;
 
-    memset(e, 0, e_len);
-    memset(f, 0, f_len);
-    memset(KEY, 0, KEY_len);
-    silc_free(e);
-    silc_free(f);
-    silc_free(KEY);
-  } else {
-    e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
+  /* Put version */
+  rp->version = strdup(version);
+  rp->version_len = strlen(version);
 
-    buf = silc_buffer_alloc_size(silc_buffer_len(ske->start_payload_copy) +
-                                ske->ke1_payload->pk_len + e_len);
-    if (!buf)
-      return SILC_SKE_STATUS_OUT_OF_MEMORY;
+  /* Get supported Key Exhange groups */
+  rp->ke_grp_list = silc_ske_get_supported_groups();
+  rp->ke_grp_len = strlen(rp->ke_grp_list);
 
-    /* Format the buffer used to compute the hash value */
-    ret =
-      silc_buffer_format(buf,
-                        SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
-                                    silc_buffer_len(ske->start_payload_copy)),
-                        SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
-                                             ske->ke1_payload->pk_len),
-                        SILC_STR_UI_XNSTRING(e, e_len),
-                        SILC_STR_END);
-    if (ret == -1) {
-      silc_buffer_free(buf);
-      memset(e, 0, e_len);
-      silc_free(e);
-      return SILC_SKE_STATUS_ERROR;
-    }
+  /* Get supported PKCS algorithms */
+  rp->pkcs_alg_list = silc_pkcs_get_supported();
+  rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
 
-    memset(e, 0, e_len);
-    silc_free(e);
-  }
+  /* Get supported encryption algorithms */
+  rp->enc_alg_list = silc_cipher_get_supported();
+  rp->enc_alg_len = strlen(rp->enc_alg_list);
 
-  /* Make the hash */
-  silc_hash_make(ske->prop->hash, buf->data, silc_buffer_len(buf),
-                return_hash);
-  *return_hash_len = silc_hash_len(ske->prop->hash);
+  /* Get supported hash algorithms */
+  rp->hash_alg_list = silc_hash_get_supported();
+  rp->hash_alg_len = strlen(rp->hash_alg_list);
 
-  if (initiator == FALSE) {
-    SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
-  } else {
-    SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
-  }
+  /* Get supported HMACs */
+  rp->hmac_alg_list = silc_hmac_get_supported();
+  rp->hmac_alg_len = strlen(rp->hmac_alg_list);
 
-  silc_buffer_free(buf);
+  /* XXX */
+  /* Get supported compression algorithms */
+  rp->comp_alg_list = strdup("none");
+  rp->comp_alg_len = strlen("none");
 
-  return status;
+  rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
+    2 + rp->version_len +
+    2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
+    2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
+    2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
+
+  return rp;
 }
 
 /* Processes the provided key material `data' as the SILC protocol
@@ -1950,6 +2127,10 @@ silc_ske_process_key_material_data(unsigned char *data,
   if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
     return NULL;
 
+  key = silc_calloc(1, sizeof(*key));
+  if (!key)
+    return NULL;
+
   buf = silc_buffer_alloc_size(1 + data_len);
   if (!buf)
     return NULL;
@@ -2129,7 +2310,6 @@ silc_ske_process_key_material(SilcSKE ske,
                              SilcUInt32 req_enc_key_len,
                              SilcUInt32 req_hmac_key_len)
 {
-  SilcSKEStatus status;
   SilcBuffer buf;
   unsigned char *tmpbuf;
   SilcUInt32 klen;
@@ -2190,6 +2370,81 @@ void silc_ske_free_key_material(SilcSKEKeyMaterial key)
   silc_free(key);
 }
 
+/* Set keys into use */
+
+SilcBool silc_ske_set_keys(SilcSKE ske,
+                          SilcSKEKeyMaterial keymat,
+                          SilcSKESecurityProperties prop,
+                          SilcCipher *ret_send_key,
+                          SilcCipher *ret_receive_key,
+                          SilcHmac *ret_hmac_send,
+                          SilcHmac *ret_hmac_receive,
+                          SilcHash *ret_hash)
+{
+  /* Allocate ciphers to be used in the communication */
+  if (ret_send_key) {
+    if (!silc_cipher_alloc((char *)silc_cipher_get_name(prop->cipher),
+                          ret_send_key))
+      return FALSE;
+  }
+  if (ret_receive_key) {
+    if (!silc_cipher_alloc((char *)silc_cipher_get_name(prop->cipher),
+                          ret_receive_key))
+      return FALSE;
+  }
+
+  /* Allocate HMACs */
+  if (ret_hmac_send) {
+    if (!silc_hmac_alloc((char *)silc_hmac_get_name(prop->hmac), NULL,
+                        ret_hmac_send))
+      return FALSE;
+  }
+  if (ret_hmac_receive) {
+    if (!silc_hmac_alloc((char *)silc_hmac_get_name(prop->hmac), NULL,
+                        ret_hmac_receive))
+      return FALSE;
+  }
+
+  /* Set key material */
+  if (ske->responder) {
+    silc_cipher_set_key(*ret_send_key, keymat->receive_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(*ret_send_key, keymat->receive_iv);
+    silc_cipher_set_key(*ret_receive_key, keymat->send_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(*ret_receive_key, keymat->send_iv);
+    silc_hmac_set_key(*ret_hmac_send, keymat->receive_hmac_key,
+                     keymat->hmac_key_len);
+    silc_hmac_set_key(*ret_hmac_receive, keymat->send_hmac_key,
+                     keymat->hmac_key_len);
+  } else {
+    silc_cipher_set_key(*ret_send_key, keymat->send_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(*ret_send_key, keymat->send_iv);
+    silc_cipher_set_key(*ret_receive_key, keymat->receive_enc_key,
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(*ret_receive_key, keymat->receive_iv);
+    silc_hmac_set_key(*ret_hmac_send, keymat->send_hmac_key,
+                     keymat->hmac_key_len);
+    silc_hmac_set_key(*ret_hmac_receive, keymat->receive_hmac_key,
+                     keymat->hmac_key_len);
+  }
+
+  /* Allocate hash */
+  if (ret_hash) {
+    if (!silc_hash_alloc(silc_hash_get_name(prop->hash), ret_hash))
+      return FALSE;
+  }
+
+  SILC_LOG_INFO(("Security properties: %s %s %s %s",
+                ret_send_key ? silc_cipher_get_name(*ret_send_key) : "??",
+                ret_hmac_send ? silc_hmac_get_name(*ret_hmac_send) : "??",
+                ret_hash ? silc_hash_get_name(*ret_hash) : "??",
+                ske->prop->flags & SILC_SKE_SP_FLAG_PFS ? "PFS" : ""));
+
+  return TRUE;
+}
+
 const char *silc_ske_status_string[] =
 {
   /* Official */
@@ -2207,9 +2462,7 @@ const char *silc_ske_status_string[] =
   "Invalid cookie",
 
   /* Other errors */
-  "Pending",
   "Remote did not provide public key",
-  "Key exchange protocol is not active",
   "Bad reserved field in packet",
   "Bad payload length in packet",
   "Error computing signature",
@@ -2235,11 +2488,11 @@ const char *silc_ske_map_status(SilcSKEStatus status)
 /* Parses remote host's version string. */
 
 SilcBool silc_ske_parse_version(SilcSKE ske,
-                           SilcUInt32 *protocol_version,
-                           char **protocol_version_string,
-                           SilcUInt32 *software_version,
-                           char **software_version_string,
-                           char **vendor_version)
+                               SilcUInt32 *protocol_version,
+                               char **protocol_version_string,
+                               SilcUInt32 *software_version,
+                               char **software_version_string,
+                               char **vendor_version)
 {
   return silc_parse_version_string(ske->remote_version,
                                   protocol_version,
index e1c25b8539afac74ba0c4ae0044bdf329a1820f4..6efd1d4577d08d9d0dc2ce897fd72cbe39fb4bed 100644 (file)
@@ -17,9 +17,6 @@
 
 */
 
-#ifndef SILCSKE_H
-#define SILCSKE_H
-
 /****h* silcske/SILC SKE Interface
  *
  * DESCRIPTION
  * server SKE is performed to exchange public keys, and to generate the key
  * that is then used as session key. Two clients can execute SKE as well
  * two create secret key material for securing for example file transfer
- * stream.
- *
- * This SKE implementation provides easy interface for application
- * that wants to use SKE. In fact, the interface is designed to be
- * application independent, and does not expect that the application using
- * SKE would actually relate in any way to SILC. Hence, the interface
- * can be used in any kind of application needing to perform key exchange
- * protocol with two parties. The network connection is also handled
- * outside the SKE interface.
- *
- * The protocol has initiator and responder. The initiator is the one
- * that starts the protocol, and the responder is the one that receives
- * negotiation request. The protocol has phases, and the interface is
- * split into several phases that the application may call when
- * needed. Heavy operations has been splitted so that application may
- * call next phase with a timeout to give processing times to other
- * things in the application. On the other hand, if application does
- * not care about this it may call the phases immediately without any
- * timeout.
+ * stream. This SKE implementation provides easy interface for application
+ * that wants to use SKE.
  *
  ***/
 
-#include "silcske_status.h"
-
-/* Length of cookie in Start Payload */
-#define SILC_SKE_COOKIE_LEN 16
+#ifndef SILCSKE_H
+#define SILCSKE_H
 
 /* Forward declarations */
 typedef struct SilcSKECallbacksStruct *SilcSKECallbacks;
 typedef struct SilcSKEStruct *SilcSKE;
 
+/****d* silcske/SilcSKEAPI/SilcSKEStatus
+ *
+ * NAME
+ *
+ *    typedef enum { ... } SilcSKEStatus;
+ *
+ * DESCRIPTION
+ *
+ *    Status types returned in SKE callbacks. This tell the status of
+ *    the SKE session, and if an error occurred. Application can map the
+ *    status to human readable string with silc_ske_map_status function.
+ *
+ * SOURCE
+ */
+typedef enum {
+  /* These are defined by the protocol */
+  SILC_SKE_STATUS_OK                     = 0,  /* No error */
+  SILC_SKE_STATUS_ERROR                  = 1,  /* Unknown error */
+  SILC_SKE_STATUS_BAD_PAYLOAD            = 2,  /* Malformed payload */
+  SILC_SKE_STATUS_UNKNOWN_GROUP          = 3,  /* Unsupported DH group */
+  SILC_SKE_STATUS_UNKNOWN_CIPHER         = 4,  /* Unsupported cipher */
+  SILC_SKE_STATUS_UNKNOWN_PKCS           = 5,  /* Unsupported PKCS algorithm */
+  SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION  = 6,  /* Unsupported hash function */
+  SILC_SKE_STATUS_UNKNOWN_HMAC           = 7,  /* Unsupported HMAC */
+  SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY = 8,  /* Unsupported/not trusted PK */
+  SILC_SKE_STATUS_INCORRECT_SIGNATURE    = 9,  /* Incorrect signature */
+  SILC_SKE_STATUS_BAD_VERSION            = 10, /* Unsupported version */
+  SILC_SKE_STATUS_INVALID_COOKIE         = 11, /* Cookie was modified */
+
+  /* Implementation specific status types */
+  SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED,     /* Remote did not send PK */
+  SILC_SKE_STATUS_BAD_RESERVED_FIELD,         /* Reserved field was not 0 */
+  SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH,         /* Payload includes garbage */
+  SILC_SKE_STATUS_SIGNATURE_ERROR,            /* Error computing signature */
+  SILC_SKE_STATUS_OUT_OF_MEMORY,              /* System out of memory */
+} SilcSKEStatus;
+/***/
+
 #include "silcske_groups.h"
 #include "silcske_payload.h"
 
@@ -94,7 +110,7 @@ typedef enum {
  *
  *    Security Properties negotiated between key exchange parties. This
  *    structure is filled from the Key Exchange Start Payload which is used
- *    to negotiate what security properties should be used in the
+ *    to negotiate what security properties must be used in the
  *    communication.
  *
  * SOURCE
@@ -102,10 +118,11 @@ typedef enum {
 typedef struct {
   SilcSKESecurityPropertyFlag flags;    /* Flags */
   SilcSKEDiffieHellmanGroup group;      /* Selected Diffie Hellman group */
-  SilcPKCS pkcs;                        /* Selected PKCS algorithm */
   SilcCipher cipher;                    /* Selected cipher */
-  SilcHash hash;                        /* Selected hash algorithm */
   SilcHmac hmac;                        /* Selected HMAC */
+  SilcHash hash;                        /* Selected hash algorithm */
+  SilcPKCS pkcs;                        /* Selected PKCS and remote's
+                                           public key/certificate */
 } *SilcSKESecurityProperties;
 /***/
 
@@ -121,6 +138,7 @@ typedef struct {
  *    application to silc_ske_process_key_material* functions. It includes
  *    the processed key material which can be used as SILC session keys.
  *
+ * SOURCE
  */
 typedef struct {
   unsigned char *send_iv;
@@ -151,6 +169,7 @@ typedef struct {
  *
  *    Application may save application specific data to `user_context'.
  *
+ * SOURCE
  */
 typedef struct {
   void *user_context;                /* Application specific data */
@@ -235,35 +254,27 @@ typedef void (*SilcSKEVerifyCb)(SilcSKE ske,
                                SilcSKEVerifyCbCompletion completion,
                                void *completion_context);
 
-/****f* silcske/SilcSKEAPI/SilcSKECheckVersion
- *
- * SYNOPSIS
- *
- *    typedef SilcSKEStatus
- *    (*SilcSKECheckVersionCb)(SilcSKE ske,
- *                             const unsigned char *version,
- *                             SilcUInt32 len, void *context);
- *
- * DESCRIPTION
- *
- *    Callback function used to check the version of the remote SKE server.
- *    The SKE library will call this function so that the appliation may
- *    check its version against the remote host's version.  This returns
- *    SILC_SKE_STATUS_OK if the version string is Ok, and returns
- *    SILC_SKE_STATUS_BAD_VERSION if the version was not acceptable.
- *
- ***/
-typedef SilcSKEStatus (*SilcSKECheckVersionCb)(SilcSKE ske,
-                                              const unsigned char *version,
-                                              SilcUInt32 len, void *context);
-
 /****f* silcske/SilcSKEAPI/SilcSKECompletionCb
  *
  * SYNOPSIS
  *
+ *    typedef void (*SilcSKECompletionCb)(SilcSKE ske,
+ *                                        SilcSKEStatus status,
+ *                                        SilcSKESecurityProperties prop,
+ *                                        SilcSKEKeyMaterial keymat,
+ *                                        SilcSKERekeyMaterial rekey,
+ *                                        void *context);
  *
  * DESCRIPTION
  *
+ *    Completion callback.  This is called after the key exchange protocol
+ *    has been completed.  It delivers the status of the protocol, and if
+ *    successful the security properties `prop' that was negotiated in the
+ *    protocol and the key material `keymat' that can be set into use by
+ *    calling silc_ske_set_keys, and the rekey key material `rekey' which
+ *    can be used later to start rekey protocol.  The `prop' will remain
+ *    valid as long as `ske' is valid.  After `ske' is freed `prop' will
+ *    become invalid.
  *
  ***/
 typedef void (*SilcSKECompletionCb)(SilcSKE ske,
@@ -273,89 +284,6 @@ typedef void (*SilcSKECompletionCb)(SilcSKE ske,
                                    SilcSKERekeyMaterial rekey,
                                    void *context);
 
-/****s* silcske/SilcSKEAPI/SilcSKEStruct
- *
- * NAME
- *
- *    struct SilcSKEStruct { ... };
- *
- * DESCRIPTION
- *
- *    This structure is the SKE session context, and has a type definition
- *    to SilcSKE. The structure includes the network connection socket,
- *    security properties collected during the SKE negotiation, payloads
- *    sent and received during the negotiation, and the actual raw key
- *    material too. The application usually does not need to reference
- *    to the inside of this structure.  However, checking the current
- *    status of the session can easily be checked with ske->status.
- *
- * SOURCE
- */
-struct SilcSKEStruct {
-  /* The network socket connection stream.  Set by application. */
-  SilcPacketStream stream;
-
-  /* Negotiated Security properties.  May be NULL in case of error. */
-  SilcSKESecurityProperties prop;
-
-  /* Key Exchange payloads filled during key negotiation with
-     remote data. Responder may save local data here as well. */
-  SilcSKEStartPayload start_payload;
-  SilcSKEKEPayload ke1_payload;
-  SilcSKEKEPayload ke2_payload;
-  unsigned char *remote_version;
-
-  /* Temporary copy of the KE Start Payload used in the
-     HASH computation. */
-  SilcBuffer start_payload_copy;
-
-  /* Random number x, 1 < x < q. This is the secret exponent
-     used in Diffie Hellman computations. */
-  SilcMPInt *x;
-
-  /* The secret shared key */
-  SilcMPInt *KEY;
-
-  /* The hash value HASH of the key exchange */
-  unsigned char *hash;
-  SilcUInt32 hash_len;
-
-  /* Random Number Generator. This is set by the caller and must
-     be free'd by the caller. */
-  SilcRng rng;
-
-  /* Pointer to the what ever user data. This is set by the caller
-     and is not touched by the SKE. The caller must also free this one. */
-  void *user_data;
-
-  /* Current status of SKE */
-  SilcSKEStatus status;
-
-  /* Reference counter. This is used when SKE library is performing async
-     operations, like public key verification. */
-  int users;
-
-  /* SKE callbacks. */
-  SilcSKECallbacks callbacks;
-
-  /* Backwards support version indicator */
-  SilcUInt32 backward_version;
-
-  char *version;
-  SilcPublicKey public_key;
-  SilcPrivateKey private_key;
-  SilcSKEPKType pk_type;
-  SilcBuffer packet_buf;
-  SilcSKESecurityPropertyFlag flags;
-  SilcSKEKeyMaterial keymat;
-  SilcSKERekeyMaterial rekey;
-  SilcSchedule schedule;
-  SilcFSMStruct fsm;
-  SilcAsyncOperationStruct op;
-  SilcBool aborted;
-};
-/***/
-
 /* Prototypes */
 
 /****f* silcske/SilcSKEAPI/silc_ske_alloc
@@ -363,7 +291,8 @@ struct SilcSKEStruct {
  * SYNOPSIS
  *
  *    SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
- *                           void *context);
+ *                           SilcPublicKey public_key,
+ *                           SilcPrivateKey private_key, void *context);
  *
  * DESCRIPTION
  *
@@ -380,7 +309,7 @@ struct SilcSKEStruct {
  *
  *    // Initiator example
  *    ske = silc_ske_alloc(rng, scheduler, app);
- *    silc_ske_set_callbacks(ske, verify_public_key, check_version, app);
+ *    silc_ske_set_callbacks(ske, verify_public_key, completion, app);
  *    start_payload =
  *      silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_PFS |
  *                                            SILC_SKE_SP_FLAG_MUTUAL,
@@ -388,7 +317,9 @@ struct SilcSKEStruct {
  *    silc_ske_initiator_start(ske);
  *
  ***/
-SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule, void *context);
+SilcSKE silc_ske_alloc(SilcRng rng, SilcSchedule schedule,
+                      SilcPublicKey public_key, SilcPrivateKey private_key,
+                      void *context);
 
 /****f* silcske/SilcSKEAPI/silc_ske_free
  *
@@ -422,7 +353,6 @@ void *silc_ske_get_context(SilcSKE ske);
  *
  *    void silc_ske_set_callbacks(SilcSKE ske,
  *                                SilcSKEVerifyCb verify_key,
- *                                SilcSKECheckVersion check_version,
  *                                SilcSKECompletion completed,
  *                                void *context);
  *
@@ -438,11 +368,6 @@ void *silc_ske_get_context(SilcSKE ske);
  *    argument since sending public key in rekey is not mandatory.  Setting
  *    this callback implies that remote end MUST send its public key.
  *
- *    The `check_version' callback is called to verify the remote host's
- *    version.  The application may check its own version against the remote
- *    host's version and determine whether supporting the remote host
- *    is possible.
- *
  *    The `completed' callback will be called once the protocol has completed,
  *    either successfully or with an error.  The status of the protocol is
  *    delivered to application with the callback.
@@ -453,7 +378,6 @@ void *silc_ske_get_context(SilcSKE ske);
  ***/
 void silc_ske_set_callbacks(SilcSKE ske,
                            SilcSKEVerifyCb verify_key,
-                           SilcSKECheckVersionCb check_version,
                            SilcSKECompletionCb completed,
                            void *context);
 
@@ -491,9 +415,9 @@ void silc_ske_set_callbacks(SilcSKE ske,
  *
  ***/
 SilcAsyncOperation
-silc_ske_initiator_start(SilcSKE ske,
-                        SilcPacketStream stream,
-                        SilcSKEStartPayload start_payload);
+silc_ske_initiator(SilcSKE ske,
+                  SilcPacketStream stream,
+                  SilcSKEStartPayload start_payload);
 
 /****f* silcske/SilcSKEAPI/silc_ske_responder_start
  *
@@ -518,11 +442,8 @@ silc_ske_initiator_start(SilcSKE ske,
  *    for `stream' after this function is called.  The `stream' is turned
  *    over to application once the completion callback is called.
  *
- *    The application has received initiator's first packet from network
- *    and it must provide it as `start_payload' argument to this function.
- *    The function processes the packet and makes security property selection
- *    from the initiator's proposal.  The `version' is the responder's version
- *    that will be sent in reply to the initiator.  The `flags' indicates
+ *    The `version' is the responder's SILC protocol version that will be
+ *    sent in reply to the initiator.  The `flags' indicates the
  *    SilcSKESecurityPropertyFlag flags that responder supports and enforces
  *    for the initiator.  Responder may, for example, enforce that the PFS
  *    will be performed in rekey.
@@ -534,22 +455,21 @@ silc_ske_initiator_start(SilcSKE ske,
  *
  ***/
 SilcAsyncOperation
-silc_ske_responder_start(SilcSKE ske,
-                        SilcPacketStream stream,
-                        const char *version,
-                        SilcBuffer start_payload,
-                        SilcSKESecurityPropertyFlag flags);
+silc_ske_responder(SilcSKE ske,
+                  SilcPacketStream stream,
+                  const char *version,
+                  SilcSKESecurityPropertyFlag flags);
 
 SilcAsyncOperation
-silc_ske_rekey_initiator_start(SilcSKE ske,
-                              SilcPacketStream stream,
-                              SilcSKERekeyMaterial rekey);
+silc_ske_rekey_initiator(SilcSKE ske,
+                        SilcPacketStream stream,
+                        SilcSKERekeyMaterial rekey);
 
 SilcAsyncOperation
-silc_ske_rekey_responder_start(SilcSKE ske,
-                              SilcPacketStream stream,
-                              SilcBuffer ke_payload,
-                              SilcSKERekeyMaterial rekey);
+silc_ske_rekey_responder(SilcSKE ske,
+                        SilcPacketStream stream,
+                        SilcBuffer ke_payload,
+                        SilcSKERekeyMaterial rekey);
 
 /****f* silcske/SilcSKEAPI/silc_ske_assemble_security_properties
  *
@@ -565,9 +485,10 @@ silc_ske_rekey_responder_start(SilcSKE ske,
  *    Assembles security properties to Key Exchange Start Payload to be
  *    sent to the remote end.  This checks system wide (SILC system, that is)
  *    settings and chooses from those.  However, if other properties
- *    should be used this function is easy to replace by another function,
- *    as, this function is called by the caller of the library and not
- *    by the SKE library itself.  Returns NULL on error.
+ *    should be used this function is easy to replace by another function.
+ *    Returns NULL on error.  This is an utility function.  This is used
+ *    by the initiator of the protocol.  The `version' is the local SILC
+ *    protocol version string.
  *
  ***/
 SilcSKEStartPayload
@@ -575,32 +496,73 @@ silc_ske_assemble_security_properties(SilcSKE ske,
                                      SilcSKESecurityPropertyFlag flags,
                                      const char *version);
 
+/****f* silcske/SilcSKEAPI/silc_ske_assemble_security_properties
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_ske_set_keys(SilcSKE ske,
+ *                               SilcSKEKeyMaterial keymat,
+ *                               SilcSKESecurityProperties prop,
+ *                               SilcCipher *ret_send_key,
+ *                               SilcCipher *ret_receive_key,
+ *                               SilcHmac *ret_hmac_send,
+ *                               SilcHmac *ret_hmac_receive,
+ *                               SilcHash *ret_hash);
+ *
+ * DESCRIPTION
+ *
+ *    This function can be used after successful key exchange to take the
+ *    key material `keymat' with security properties `prop' into use.
+ *    This will allocate send and receive ciphers, HMACs and hash for the
+ *    application.  Caller must free the returned contexts.  This is an
+ *    utility function.
+ *
+ ***/
+SilcBool silc_ske_set_keys(SilcSKE ske,
+                          SilcSKEKeyMaterial keymat,
+                          SilcSKESecurityProperties prop,
+                          SilcCipher *ret_send_key,
+                          SilcCipher *ret_receive_key,
+                          SilcHmac *ret_hmac_send,
+                          SilcHmac *ret_hmac_receive,
+                          SilcHash *ret_hash);
+
 /****f* silcske/SilcSKEAPI/silc_ske_parse_version
  *
  * SYNOPSIS
  *
  *    SilcBool silc_ske_parse_version(SilcSKE ske,
- *                                SilcUInt32 *protocol_version,
- *                                char **protocol_version_string,
- *                                SilcUInt32 *software_version,
- *                                char **software_version_string,
- *                                char **vendor_version);
+ *                                    SilcUInt32 *protocol_version,
+ *                                    char **protocol_version_string,
+ *                                    SilcUInt32 *software_version,
+ *                                    char **software_version_string,
+ *                                    char **vendor_version);
  *
  * DESCRIPTION
  *
- *    This utility function can be used to parse the remote host's version
- *    string.  This returns the protocol version, and software version into
- *    the `protocol_version', `software_version' and `vendor_version' pointers
- *    if they are provided.  The string versions of the versions are saved
- *    in *_string pointers if they are provided.  Returns TRUE if the version
- *    string was successfully parsed.
+ *    Utility function to parse the remote host's version string.
  *
  ***/
 SilcBool silc_ske_parse_version(SilcSKE ske,
-                           SilcUInt32 *protocol_version,
-                           char **protocol_version_string,
-                           SilcUInt32 *software_version,
-                           char **software_version_string,
-                           char **vendor_version);
+                               SilcUInt32 *protocol_version,
+                               char **protocol_version_string,
+                               SilcUInt32 *software_version,
+                               char **software_version_string,
+                               char **vendor_version);
+
+/****f* silcske/SilcSKEAPI/silc_ske_map_status
+ *
+ * SYNOPSIS
+ *
+ *    const char *silc_ske_map_status(SilcSKEStatus status);
+ *
+ * DESCRIPTION
+ *
+ *    Utility function to map the `status' into human readable message.
+ *
+ ***/
+const char *silc_ske_map_status(SilcSKEStatus status);
+
+#include "silcske_i.h"
 
 #endif /* !SILCSKE_H */
index 551bf16834beaf6697b9b37c447d98ddc97dd3da..09c837c656fd03fb2d55cf6f9fecde703861060a 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcske_groups.h 
+  silcske_groups.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2000 - 2002 Pekka Riikonen
+  Copyright (C) 2000 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
 #ifndef SILCSKE_GROUPS_H
 #define SILCSKE_GROUPS_H
 
-#include "silcske_status.h"
-
 /****s* silcske/SilcSKEGroups/SilcSKEDiffieHellmanGroup
  *
  * NAME
- * 
- *    typedef struct SilcSKEDiffieHellmanGroupStruct 
+ *
+ *    typedef struct SilcSKEDiffieHellmanGroupStruct
  *                     *SilcSKEDiffieHellmanGroup;
  *
  * DESCRIPTION
@@ -55,7 +53,7 @@ typedef struct SilcSKEDiffieHellmanGroupStruct *SilcSKEDiffieHellmanGroup;
  *
  * SYNOPSIS
  *
- *    SilcSKEStatus 
+ *    SilcSKEStatus
  *    silc_ske_group_get_by_number(int number,
  *                                 SilcSKEDiffieHellmanGroup *ret);
  *
@@ -73,7 +71,7 @@ SilcSKEStatus silc_ske_group_get_by_number(int number,
  *
  * SYNOPSIS
  *
- *    SilcSKEStatus 
+ *    SilcSKEStatus
  *    silc_ske_get_group_by_name(const char *name,
  *                               SilcSKEDiffieHellmanGroup *ret);
  *
diff --git a/lib/silcske/silcske_status.h b/lib/silcske/silcske_status.h
deleted file mode 100644 (file)
index 4eb3371..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
-
-  silcske_status.h 
-
-  Author: Pekka Riikonen <priikone@silcnet.org>
-
-  Copyright (C) 2000 - 2002 Pekka Riikonen
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; version 2 of the License.
-
-  This program 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 General Public License for more details.
-
-*/
-
-/****h* silcske/SKE Status Types
- *
- * DESCRIPTION
- *
- * Defines the SilcSKEStatus type, that is returned by all SKE routines,
- * and a utility interface for handling the status.
- *
- ***/
-
-#ifndef SILCSKE_STATUS_H
-#define SILCSKE_STATUS_H
-
-/****d* silcske/SilcSKEStatuses/SilcSKEStatus
- *
- * NAME
- * 
- *    typedef enum { ... } SilcSKEStatus;
- *
- * DESCRIPTION
- *
- *    Status types returned by all SKE routines. This tell the status of
- *    the SKE session, and if an error occurred. 
- *
- * SOURCE
- */
-typedef enum {
-  /* These are defined by the protocol */
-  SILC_SKE_STATUS_OK                     = 0,  /* No error */
-  SILC_SKE_STATUS_ERROR                  = 1,  /* Unknown error */
-  SILC_SKE_STATUS_BAD_PAYLOAD            = 2,  /* Malformed payload */
-  SILC_SKE_STATUS_UNKNOWN_GROUP          = 3,  /* Unsupported DH group */
-  SILC_SKE_STATUS_UNKNOWN_CIPHER         = 4,  /* Unsupported cipher */
-  SILC_SKE_STATUS_UNKNOWN_PKCS           = 5,  /* Unsupported PKCS algorithm */
-  SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION  = 6,  /* Unsupported hash function */
-  SILC_SKE_STATUS_UNKNOWN_HMAC           = 7,  /* Unsupported HMAC */
-  SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY = 8,  /* Unsupported/not trusted PK */
-  SILC_SKE_STATUS_INCORRECT_SIGNATURE    = 9,  /* Incorrect signature */
-  SILC_SKE_STATUS_BAD_VERSION            = 10, /* Unsupported version */
-  SILC_SKE_STATUS_INVALID_COOKIE         = 11, /* Cookie was modified */
-
-  /* Implementation specific status types */
-  SILC_SKE_STATUS_PENDING,                    /* SKE library is pending */
-  SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED,     /* Remote did not send PK */
-  SILC_SKE_STATUS_KEY_EXCHANGE_NOT_ACTIVE,     /* SKE is not started */
-  SILC_SKE_STATUS_BAD_RESERVED_FIELD,         /* Reserved field was not 0 */
-  SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH,         /* Payload includes garbage */
-  SILC_SKE_STATUS_SIGNATURE_ERROR,            /* Error computing signature */
-  SILC_SKE_STATUS_OUT_OF_MEMORY,              /* System out of memory */
-
-  /* Other internal status types */
-  SILC_SKE_STATUS_FREED,                      /* Internal library status */
-} SilcSKEStatus;
-/***/
-
-/****f* silcske/SilcSKEStatuses/silc_ske_map_status
- *
- * SYNOPSIS
- *
- *    const char *silc_ske_map_status(SilcSKEStatus status);
- *
- * DESCRIPTION
- *
- *    Utility function to map the `status' into human readable message.
- *
- ***/
-const char *silc_ske_map_status(SilcSKEStatus status);
-
-#endif /* SILCSKE_STATUS_H */
diff --git a/lib/silcskr/Makefile.ad b/lib/silcskr/Makefile.ad
new file mode 100644 (file)
index 0000000..26c9a6a
--- /dev/null
@@ -0,0 +1,30 @@
+#
+#  Makefile.ad
+#
+#  Author: Pekka Riikonen <priikone@silcnet.org>
+#
+#  Copyright (C) 2005 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; version 2 of the License.
+#
+#  This program 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 General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LTLIBRARIES = libsilcskr.la
+
+libsilcskr_la_SOURCES = silcskr.c
+
+#ifdef SILC_DIST_TOOLKIT
+include_HEADERS = silcskr.h silcskr_i.h
+#endif SILC_DIST_TOOLKIT
+
+EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
+
+include $(top_srcdir)/Makefile.defines.in
diff --git a/lib/silcskr/silcskr.c b/lib/silcskr/silcskr.c
new file mode 100644 (file)
index 0000000..1d17c62
--- /dev/null
@@ -0,0 +1,844 @@
+/*
+
+  silcskr.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#include "silc.h"
+#include "silcskr.h"
+
+/************************** Types and definitions ***************************/
+
+/* Search constraints */
+typedef enum {
+  SILC_SKR_FIND_PKCS_TYPE,
+  SILC_SKR_FIND_USERNAME,
+  SILC_SKR_FIND_HOST,
+  SILC_SKR_FIND_REALNAME,
+  SILC_SKR_FIND_EMAIL,
+  SILC_SKR_FIND_ORG,
+  SILC_SKR_FIND_COUNTRY,
+  SILC_SKR_FIND_PUBLIC_KEY,
+  SILC_SKR_FIND_CONTEXT,
+  SILC_SKR_FIND_USAGE,         /* Never added as key specific */
+} SilcSKRFindType;
+
+/* Hash table key context */
+typedef struct {
+  SilcSKRFindType type;                /* Type of key */
+  void *data;                  /* Hash table key */
+} *SilcSKREntry, SilcSKREntryStruct;
+
+/* Foreach user context when finding entries from hash table */
+typedef struct {
+  SilcDList list;
+  void *key_context;
+  SilcSKRKeyUsage usage;
+} SilcSKRFindForeach;
+
+#if defined(SILC_DEBUG)
+static const char *find_name[] = {
+  "PKCS TYPE",
+  "USERNAME",
+  "HOST",
+  "REALNAME",
+  "EMAIL",
+  "ORG",
+  "COUNTRY",
+  "PUBLIC KEY",
+  "CONTEXT",
+  "USAGE",
+  NULL
+};
+#endif /* SILC_DEBUG */
+
+/************************ Static utility functions **************************/
+
+#if defined(SILC_DEBUG)
+
+/* Returns search constraint string */
+
+static void silc_skr_type_string(SilcSKRFindType type, void *data,
+                                char *retbuf, SilcUInt32 retbuf_size)
+{
+  switch (type) {
+  case SILC_SKR_FIND_PKCS_TYPE:
+  case SILC_SKR_FIND_USAGE:
+    snprintf(retbuf, retbuf_size, "[%s] [%d]", find_name[type],
+            (int)SILC_PTR_TO_32(data));
+    break;
+
+  case SILC_SKR_FIND_PUBLIC_KEY:
+    snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type],
+            ((SilcPublicKey)data)->identifier);
+    break;
+
+  default:
+    snprintf(retbuf, retbuf_size, "[%s] [%s]", find_name[type],
+            (char *)data);
+  }
+}
+
+#endif /* SILC_DEBUG */
+
+/* Hash table destructor for search constraints */
+
+static void silc_skr_find_destructor(void *key, void *context,
+                                    void *user_context)
+{
+  SilcSKRFindType type = SILC_PTR_TO_32(key);
+
+  switch (type) {
+  case SILC_SKR_FIND_PKCS_TYPE:
+  case SILC_SKR_FIND_USAGE:
+  case SILC_SKR_FIND_CONTEXT:
+    break;
+
+  case SILC_SKR_FIND_PUBLIC_KEY:
+    silc_pkcs_public_key_free(context);
+    break;
+
+  default:
+    silc_free(context);
+  }
+}
+
+/* Hash table destructor for key entries */
+
+static void silc_skr_destructor(void *key, void *context, void *user_context)
+{
+  SilcSKREntry type = key;
+  SilcSKRKeyInternal entry = context;
+
+  /* Destroy search data, except for SILC_SKR_FIND_PUBLIC_KEY because it
+     shares same context with the key entry. */
+  if (SILC_PTR_TO_32(type->type) != SILC_SKR_FIND_PUBLIC_KEY)
+    silc_skr_find_destructor(SILC_32_TO_PTR(type->type), type->data, NULL);
+  silc_free(type);
+
+  /* Destroy key */
+  entry->refcnt--;
+  if (entry->refcnt == 0) {
+    switch (entry->key.pk_type) {
+    case SILC_PKCS_SILC:
+      silc_pkcs_public_key_free(entry->key.key);
+      break;
+
+    default:
+      break;
+    }
+
+    silc_free(entry);
+  }
+}
+
+/* Hash table hash function for key entries */
+
+static SilcUInt32 silc_skr_hash(void *key, void *user_context)
+{
+  SilcSKREntry type = key;
+
+  switch (type->type) {
+  case SILC_SKR_FIND_PKCS_TYPE:
+  case SILC_SKR_FIND_CONTEXT:
+    return type->type + (type->type ^ SILC_PTR_TO_32(type->data));
+    break;
+
+  case SILC_SKR_FIND_PUBLIC_KEY:
+    return type->type + silc_hash_public_key(type->data, user_context);
+    break;
+
+  default:
+    break;
+  }
+
+  return type->type + silc_hash_string(type->data, user_context);
+}
+
+/* Hash table comparison function for key entries */
+
+static SilcBool silc_skr_compare(void *key1, void *key2, void *user_context)
+{
+  SilcSKREntry type1 = key1;
+  SilcSKREntry type2 = key2;
+
+  if (type1->type != type2->type)
+    return FALSE;
+
+  switch (type1->type) {
+  case SILC_SKR_FIND_PKCS_TYPE:
+  case SILC_SKR_FIND_CONTEXT:
+    return type1->data == type2->data;
+    break;
+
+  case SILC_SKR_FIND_PUBLIC_KEY:
+    return silc_hash_public_key_compare(type1->data, type2->data,
+                                       user_context);
+    break;
+
+  default:
+    break;
+  }
+
+  return silc_utf8_strcasecmp((const char *)type1->data,
+                             (const char *)type2->data);
+}
+
+/* Foreach function for finding entries in the repository */
+
+static void silc_skr_find_foreach(void *key, void *context,
+                                 void *user_context)
+{
+  SilcSKRFindForeach *f = user_context;
+  SilcSKRKeyInternal k = context;
+
+  if (k) {
+    /* If key context is present, it must match the context in the key.
+       This is used only internally when adding keys, to check if the key
+       is added with same context. */
+    if (f->key_context && f->key_context != k->key.key_context)
+      return;
+
+    /* Check for usage bits.  At least one usage bit must be set. */
+    if (f->usage && k->key.usage && (f->usage & k->key.usage) == 0)
+      return;
+
+    silc_dlist_add(f->list, k);
+  }
+}
+
+/* Finds entry from repository by search constraint type and data */
+
+static SilcBool silc_skr_find_entry(SilcSKR skr,
+                                   SilcSKRStatus *status,
+                                   SilcSKRFindType type,
+                                   void *type_data,
+                                   SilcDList *results,
+                                   void *key_context,
+                                   SilcSKRKeyUsage usage)
+{
+  SilcSKREntryStruct find;
+  SilcSKRFindForeach f;
+
+  f.list = silc_dlist_init();
+  if (!f.list) {
+    *status |= SILC_SKR_NO_MEMORY;
+    return FALSE;
+  }
+  f.key_context = key_context;
+  f.usage = usage;
+
+  find.type = type;
+  find.data = type_data;
+
+  silc_hash_table_find_foreach(skr->keys, (void *)&find,
+                              silc_skr_find_foreach, &f);
+
+  if (!silc_dlist_count(f.list)) {
+    *status |= SILC_SKR_NOT_FOUND;
+    silc_dlist_uninit(f.list);
+    return FALSE;
+  }
+
+  if (results)
+    *results = f.list;
+  else
+    silc_dlist_uninit(f.list);
+
+  return TRUE;
+}
+
+/* Add a key by search constraint type to repository */
+
+static SilcBool silc_skr_add_entry(SilcSKR skr, SilcSKRFindType type,
+                                  void *type_data, SilcSKRKeyInternal key)
+{
+  SilcSKREntry entry;
+
+  entry = silc_calloc(1, sizeof(*entry));
+  if (!entry)
+    return FALSE;
+
+  entry->type = type;
+  entry->data = type_data;
+
+  return silc_hash_table_add(skr->keys, entry, key);
+}
+
+/* Add SILC style public key to repository */
+
+static SilcSKRStatus silc_skr_add_silc(SilcSKR skr,
+                                      SilcPublicKey public_key,
+                                      SilcSKRKeyUsage usage,
+                                      void *key_context)
+{
+  SilcPublicKeyIdentifier ident = NULL;
+  SilcSKRKeyInternal key;
+  SilcSKRStatus status = SILC_SKR_ERROR;
+
+  SILC_LOG_DEBUG(("Adding SILC public key [%s]", public_key->identifier));
+
+  silc_mutex_lock(skr->lock);
+
+  /* Check that this key hasn't been added already */
+  if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
+                         public_key, NULL, key_context, 0)) {
+    silc_mutex_unlock(skr->lock);
+    SILC_LOG_DEBUG(("Key already added"));
+    return status;
+  }
+
+  /* Allocate key entry */
+  key = silc_calloc(1, sizeof(*key));
+  if (!key) {
+    silc_mutex_unlock(skr->lock);
+    return status | SILC_SKR_NO_MEMORY;
+  }
+
+  key->key.usage = usage;
+  key->key.pk_type = public_key->pk_type;
+  key->key.key = public_key;
+  key->key.key_context = key_context;
+
+  ident = silc_pkcs_decode_identifier(public_key->identifier);
+  if (!ident) {
+    silc_mutex_unlock(skr->lock);
+    silc_pkcs_free_identifier(ident);
+    return status | SILC_SKR_NO_MEMORY;
+  }
+
+  /* Add key specifics */
+
+  if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
+                         public_key, key))
+    goto err;
+  key->refcnt++;
+
+  if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PKCS_TYPE,
+                         SILC_32_TO_PTR(public_key->pk_type), key))
+    goto err;
+  key->refcnt++;
+
+  if (ident->username) {
+    if (!silc_skr_add_entry(skr, SILC_SKR_FIND_USERNAME,
+                           ident->username, key))
+      goto err;
+    key->refcnt++;
+  }
+
+  if (ident->host) {
+    if (!silc_skr_add_entry(skr, SILC_SKR_FIND_HOST,
+                           ident->host, key))
+      goto err;
+    key->refcnt++;
+  }
+
+  if (ident->realname) {
+    if (!silc_skr_add_entry(skr, SILC_SKR_FIND_REALNAME,
+                           ident->realname, key))
+      goto err;
+    key->refcnt++;
+  }
+
+  if (ident->email) {
+    if (!silc_skr_add_entry(skr, SILC_SKR_FIND_EMAIL,
+                           ident->email, key))
+      goto err;
+    key->refcnt++;
+  }
+
+  if (ident->org) {
+    if (!silc_skr_add_entry(skr, SILC_SKR_FIND_ORG,
+                           ident->org, key))
+      goto err;
+    key->refcnt++;
+  }
+
+  if (ident->country) {
+    if (!silc_skr_add_entry(skr, SILC_SKR_FIND_COUNTRY,
+                           ident->country, key))
+      goto err;
+    key->refcnt++;
+  }
+
+  if (key_context) {
+    if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
+                           key_context, key))
+      goto err;
+    key->refcnt++;
+  }
+
+  silc_mutex_unlock(skr->lock);
+
+  silc_free(ident);
+  return SILC_SKR_OK;
+
+ err:
+  silc_mutex_unlock(skr->lock);
+  silc_free(ident);
+  return status;
+}
+
+/* Add SILC style public key to repository, and only the public key, not
+   other details from the key. */
+
+static SilcSKRStatus silc_skr_add_silc_simple(SilcSKR skr,
+                                             SilcPublicKey public_key,
+                                             SilcSKRKeyUsage usage,
+                                             void *key_context)
+{
+  SilcSKRKeyInternal key;
+  SilcSKRStatus status = SILC_SKR_ERROR;
+
+  SILC_LOG_DEBUG(("Adding SILC public key [%s]", public_key->identifier));
+
+  silc_mutex_lock(skr->lock);
+
+  /* Check that this key hasn't been added already */
+  if (silc_skr_find_entry(skr, &status, SILC_SKR_FIND_PUBLIC_KEY,
+                         public_key, NULL, key_context, 0)) {
+    silc_mutex_unlock(skr->lock);
+    SILC_LOG_DEBUG(("Key already added"));
+    return status;
+  }
+
+  /* Allocate key entry */
+  key = silc_calloc(1, sizeof(*key));
+  if (!key) {
+    silc_mutex_unlock(skr->lock);
+    return status | SILC_SKR_NO_MEMORY;
+  }
+
+  key->key.usage = usage;
+  key->key.pk_type = public_key->pk_type;
+  key->key.key = public_key;
+  key->key.key_context = key_context;
+
+  /* Add key specifics */
+
+  if (!silc_skr_add_entry(skr, SILC_SKR_FIND_PUBLIC_KEY,
+                         public_key, key))
+    goto err;
+  key->refcnt++;
+
+  if (key_context) {
+    if (!silc_skr_add_entry(skr, SILC_SKR_FIND_CONTEXT,
+                           key_context, key))
+      goto err;
+    key->refcnt++;
+  }
+
+  silc_mutex_unlock(skr->lock);
+
+  return SILC_SKR_OK;
+
+ err:
+  silc_mutex_unlock(skr->lock);
+  return status;
+}
+
+/* This performs AND operation.  Any entry already in `results' that is not
+   in `list' will be removed from `results'. */
+
+static SilcBool silc_skr_results_and(SilcDList list, SilcSKRStatus *status,
+                                    SilcDList *results)
+{
+  SilcSKRKeyInternal entry, r;
+
+  if (*results == NULL) {
+    *results = silc_dlist_init();
+    if (*results == NULL) {
+      *status |= SILC_SKR_NO_MEMORY;
+      return FALSE;
+    }
+  }
+
+  /* If results is empty, just add all entries from list to results */
+  if (!silc_dlist_count(*results)) {
+    silc_dlist_start(list);
+    while ((entry = silc_dlist_get(list)) != SILC_LIST_END)
+      silc_dlist_add(*results, entry);
+
+    return TRUE;
+  }
+
+  silc_dlist_start(*results);
+  while ((entry = silc_dlist_get(*results)) != SILC_LIST_END) {
+
+    /* Check if this entry is in list  */
+    silc_dlist_start(list);
+    while ((r = silc_dlist_get(list)) != SILC_LIST_END) {
+      if (r == entry)
+       break;
+    }
+    if (r != SILC_LIST_END)
+      continue;
+
+    /* Remove from results */
+    silc_dlist_del(*results, entry);
+  }
+
+  /* If results became empty, we did not find any key */
+  if (!silc_dlist_count(*results)) {
+    SILC_LOG_DEBUG(("Not all search constraints found"));
+    *status |= SILC_SKR_NOT_FOUND;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+
+/**************************** Key Repository API ****************************/
+
+/* Allocate key repository */
+
+SilcSKR silc_skr_alloc(SilcSchedule scheduler)
+{
+  SilcSKR skr;
+
+  skr = silc_calloc(1, sizeof(*skr));
+  if (!skr)
+    return NULL;
+
+  if (!silc_skr_init(skr, scheduler)) {
+    silc_skr_free(skr);
+    return NULL;
+  }
+
+  return skr;
+}
+
+/* Free key repository */
+
+void silc_skr_free(SilcSKR skr)
+{
+  silc_skr_uninit(skr);
+  silc_free(skr);
+}
+
+/* Initializes key repository */
+
+SilcBool silc_skr_init(SilcSKR skr, SilcSchedule scheduler)
+{
+  if (!scheduler)
+    return FALSE;
+
+  skr->scheduler = scheduler;
+
+  if (!silc_mutex_alloc(&skr->lock))
+    return FALSE;
+
+  skr->keys = silc_hash_table_alloc(0, silc_skr_hash, NULL,
+                                   silc_skr_compare, NULL,
+                                   silc_skr_destructor, NULL, TRUE);
+  if (!skr->keys)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Uninitializes key repository */
+
+void silc_skr_uninit(SilcSKR skr)
+{
+  if (skr->keys)
+    silc_hash_table_free(skr->keys);
+  silc_mutex_free(skr->lock);
+}
+
+/* Adds public key to key repository */
+
+SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
+                                     SilcPublicKey public_key,
+                                     SilcSKRKeyUsage usage,
+                                     void *key_context)
+{
+  if (!public_key)
+    return SILC_SKR_ERROR;
+
+  SILC_LOG_DEBUG(("Adding public key to repository"));
+
+  switch (public_key->pk_type) {
+
+  case SILC_PKCS_SILC:
+    return silc_skr_add_silc(skr, public_key, usage, key_context);
+    break;
+
+  default:
+    break;
+  }
+
+  return SILC_SKR_ERROR;
+}
+
+/* Adds public key to repository. */
+
+SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
+                                            SilcPublicKey public_key,
+                                            SilcSKRKeyUsage usage,
+                                            void *key_context)
+{
+  if (!public_key)
+    return SILC_SKR_ERROR;
+
+  SILC_LOG_DEBUG(("Adding public key to repository"));
+
+  switch (public_key->pk_type) {
+
+  case SILC_PKCS_SILC:
+    return silc_skr_add_silc_simple(skr, public_key, usage, key_context);
+    break;
+
+  default:
+    break;
+  }
+
+  return SILC_SKR_ERROR;
+}
+
+
+/************************** Search Constraints API **************************/
+
+/* Allocate search constraints */
+
+SilcSKRFind silc_skr_find_alloc(void)
+{
+  SilcSKRFind find;
+
+  find = silc_calloc(1, sizeof(*find));
+  if (!find)
+    return NULL;
+
+  find->constr = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL,
+                                      silc_skr_find_destructor, NULL, TRUE);
+  if (!find->constr) {
+    silc_skr_find_free(find);
+    return NULL;
+  }
+
+  return find;
+}
+
+/* Free search constraints */
+
+void silc_skr_find_free(SilcSKRFind find)
+{
+  if (find->constr)
+    silc_hash_table_free(find->constr);
+  silc_free(find);
+}
+
+SilcBool silc_skr_find_set_pkcs_type(SilcSKRFind find, SilcPKCSType type)
+{
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_PKCS_TYPE),
+                            SILC_32_TO_PTR(type));
+}
+
+SilcBool silc_skr_find_set_username(SilcSKRFind find, const char *username)
+{
+  void *c = silc_memdup(username, strlen(username));
+  if (!c)
+    return FALSE;
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_USERNAME), c);
+}
+
+SilcBool silc_skr_find_set_host(SilcSKRFind find, const char *host)
+{
+  void *c = silc_memdup(host, strlen(host));
+  if (!c)
+    return FALSE;
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_HOST), c);
+}
+
+SilcBool silc_skr_find_set_realname(SilcSKRFind find, const char *realname)
+{
+  void *c = silc_memdup(realname, strlen(realname));
+  if (!c)
+    return FALSE;
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_REALNAME), c);
+}
+
+SilcBool silc_skr_find_set_email(SilcSKRFind find, const char *email)
+{
+  void *c = silc_memdup(email, strlen(email));
+  if (!c)
+    return FALSE;
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_EMAIL), c);
+}
+
+SilcBool silc_skr_find_set_org(SilcSKRFind find, const char *org)
+{
+  void *c = silc_memdup(org, strlen(org));
+  if (!c)
+    return FALSE;
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_ORG), c);
+}
+
+SilcBool silc_skr_find_set_country(SilcSKRFind find, const char *country)
+{
+  void *c = silc_memdup(country, strlen(country));
+  if (!c)
+    return FALSE;
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_COUNTRY), c);
+}
+
+SilcBool silc_skr_find_set_public_key(SilcSKRFind find,
+                                     SilcPublicKey public_key)
+{
+  SilcPublicKey pk = silc_pkcs_public_key_copy(public_key);
+  if (!pk)
+    return FALSE;
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_PUBLIC_KEY), pk);
+}
+
+SilcBool silc_skr_find_set_context(SilcSKRFind find, void *context)
+{
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_CONTEXT), context);
+}
+
+SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage)
+{
+  if (!usage)
+    return TRUE;
+  return silc_hash_table_add(find->constr,
+                            SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
+                            SILC_32_TO_PTR(usage));
+}
+
+/******************************** Search API ********************************/
+
+/* Finds key(s) by the set search constraints.  The callback will be called
+   once keys has been found. */
+/* This is now synchronous function but may later change async */
+
+SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find,
+                                SilcSKRFindCallback callback,
+                                void *callback_context)
+{
+  SilcSKRStatus status = SILC_SKR_ERROR;
+  SilcHashTableList htl;
+  SilcDList list, results = NULL;
+  void *type, *ctx, *usage = NULL;
+
+  SILC_LOG_DEBUG(("Finding key from repository"));
+
+  if (!find || !callback)
+    return NULL;
+
+  silc_mutex_lock(skr->lock);
+
+  /* Get usage bits, if searching by them */
+  silc_hash_table_find(find->constr, SILC_32_TO_PTR(SILC_SKR_FIND_USAGE),
+                      NULL, &usage);
+
+  silc_hash_table_list(find->constr, &htl);
+  while (silc_hash_table_get(&htl, &type, &ctx)) {
+
+#if defined(SILC_DEBUG)
+    char tmp[256];
+    memset(tmp, 0, sizeof(tmp));
+    silc_skr_type_string((SilcSKRFindType)SILC_32_TO_PTR(type),
+                        ctx, tmp, sizeof(tmp) - 1);
+    SILC_LOG_DEBUG(("Finding key by %s", tmp));
+#endif /* SILC_DEBUG */
+
+    /* SILC_SKR_FIND_USAGE is handled separately while searching the keys. */
+    if ((SilcSKRFindType)SILC_32_TO_PTR(type) == SILC_SKR_FIND_USAGE)
+      continue;
+
+    /* Find entries by this search constraint */
+    if (!silc_skr_find_entry(skr, &status,
+                            (SilcSKRFindType)SILC_32_TO_PTR(type),
+                            ctx, &list, NULL, SILC_PTR_TO_32(usage))) {
+      SILC_LOG_DEBUG(("Not found"));
+      if (results) {
+       silc_dlist_uninit(results);
+       results = NULL;
+      }
+      break;
+    }
+
+    /* For now, our logic rule is AND.  All constraints must be found
+       to find the key.  Later OR might be added also. */
+    if (!silc_skr_results_and(list, &status, &results)) {
+      SILC_LOG_DEBUG(("Not found"));
+      if (results) {
+       silc_dlist_uninit(results);
+       results = NULL;
+      }
+      silc_dlist_uninit(list);
+      break;
+    }
+
+    silc_dlist_uninit(list);
+  }
+  silc_hash_table_list_reset(&htl);
+
+  silc_mutex_unlock(skr->lock);
+
+  /* Return results */
+  if (!results) {
+    callback(skr, find, status, NULL, callback_context);
+  } else {
+    silc_dlist_start(results);
+    callback(skr, find, SILC_SKR_OK, results, callback_context);
+  }
+
+  return NULL;
+}
+
+/* Helper function to find specificly SILC style public keys */
+
+SilcAsyncOperation silc_skr_find_silc(SilcSKR skr,
+                                     SilcPublicKey public_key,
+                                     SilcSKRFindCallback callback,
+                                     void *callback_context)
+{
+  SilcSKRFind find = NULL;
+  SilcAsyncOperation op;
+
+  SILC_LOG_DEBUG(("Finding SILC public key"));
+
+  if (!public_key || public_key->pk_type != SILC_PKCS_SILC)
+    goto err;
+
+  find = silc_skr_find_alloc();
+  if (!find)
+    goto err;
+
+  if (!silc_skr_find_set_public_key(find, public_key))
+    goto err;
+
+  op = silc_skr_find(skr, find, callback, callback_context);
+
+  return op;
+
+ err:
+  if (find)
+    silc_skr_find_free(find);
+  callback(skr, NULL, SILC_SKR_ERROR, NULL, callback_context);
+  return NULL;
+}
diff --git a/lib/silcskr/silcskr.h b/lib/silcskr/silcskr.h
new file mode 100644 (file)
index 0000000..a2e9abf
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+
+  silcskr.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+/****h* silcskr/SILC Key Repository
+ *
+ * DESCRIPTION
+ *
+ * SILC Key Repository
+ *
+ * SILC Key Repository is thread safe.  Same key repository context can be
+ * safely used in multi threaded environment.
+ *
+ ***/
+
+#ifndef SILCSKR_H
+#define SILCSKR_H
+
+/****s* silcskr/SilcSKRAPI/SilcSKR
+ *
+ * NAME
+ *
+ *    typedef struct SilcSKRObject *SilcSKR, SilcSKRStruct;
+ *
+ * DESCRIPTION
+ *
+ *    This context is the actual SILC Key Repository and is allocated
+ *    by silc_skr_alloc (or initialized by silc_skr_init) and given as
+ *    attribute to all silc_skr_* functions.  It is freed by the
+ *    silc_skr_free (or uninitialized with silc_skr_uninit) function.
+ *
+ ***/
+typedef struct SilcSKRObject *SilcSKR, SilcSKRStruct;
+
+/****s* silcskr/SilcSKRAPI/SilcSKRFind
+ *
+ * NAME
+ *
+ *    typedef struct SilcSKRFindStruct *SilcSKRFind
+ *
+ * DESCRIPTION
+ *
+ *    This context contains the search constraints used find keys from the
+ *    key repository.  It is allocated by silc_skr_find_alloc and freed
+ *    by silc_skr_find_free.  The context is given as argument to all
+ *    silc_skr_find* functions.
+ *
+ ***/
+typedef struct SilcSKRFindStruct *SilcSKRFind;
+
+/****d* silcskr/SilcSKRAPI/SilcSKRKeyUsage
+ *
+ * NAME
+ *
+ *    typedef enum { ... } SilcSKRKeyUsage;
+ *
+ * DESCRIPTION
+ *
+ *    Indicates the usage of the key.  Keys can be added for different
+ *    reasons and for different purpose to the repository.  SilcSKRKeyUsage
+ *    indicates what for the key exists in the repository.  The default
+ *    usage is SILC_SKR_USAGE_ANY and allows any kind of usage for the key.
+ *    If the usage should be limited then specific usage bitmask can be
+ *    specified when adding the key.  When searching keys from the
+ *    repository at least one of the key usage bits must be found in order
+ *    to find the key.
+ *
+ * SOURCE
+ */
+typedef enum {
+  SILC_SKR_USAGE_ANY            = 0x0000,  /* Any usage */
+  SILC_SKR_USAGE_AUTH           = 0x0001,  /* Signatures/verification */
+  SILC_SKR_USAGE_ENC            = 0x0002,  /* Encryption/decryption */
+  SILC_SKR_USAGE_KEY_AGREEMENT  = 0x0004,  /* Key agreement protocol */
+  SILC_SKR_USAGE_IDENTIFICATION = 0x0008,  /* Identifying key owner */
+} SilcSKRKeyUsage;
+/***/
+
+/****s* silcskr/SilcSKRAPI/SilcSKRKey
+ *
+ * NAME
+ *
+ *    typedef struct SilcSKRKeyStruct { ... } *SilcSKRKey
+ *
+ * DESCRIPTION
+ *
+ *    This context holds the public key cryptosystem key type and the key
+ *    context that has been saved in the key repository.  This context is
+ *    returned in the SilcSKRFindCallback list.  Each entry in the list is
+ *    SilcSKRKey.
+ *
+ *    The key context saved in SilcSKRKey is based on the PKCS type and
+ *    caller can explicitly type cast the key to correct type based on the
+ *    PKCS type.
+ *
+ * SOURCE
+ *
+ */
+typedef struct SilcSKRKeyStruct {
+  SilcSKRKeyUsage usage;       /* Key usage */
+  SilcPKCSType pk_type;                /* PKCS type */
+  void *key;                   /* SILC_PKCS_SILC: SilcPublicKey */
+  void *key_context;           /* Optional key specific context */
+} *SilcSKRKey;
+/***/
+
+/****d* silcskr/SilcSKRAPI/SilcSKRStatus
+ *
+ * NAME
+ *
+ *    typedef enum { ... } SilcSKRStatus;
+ *
+ * DESCRIPTION
+ *
+ *    Indicates the status of the key repository procedures.  This is
+ *    returned to SilcSKRFindCallback function to indicate the status
+ *    of the finding.  This is a bitmask, and more than one status may
+ *    be set at one time.
+ *
+ *    If there are no errors only SILC_SKR_OK is set.  If error occurred
+ *    then at least SILC_SKR_ERROR is set, and possibly other error
+ *    status also.
+ *
+ * SOURCE
+ */
+typedef enum {
+  SILC_SKR_OK                 = 0x00000001, /* All is Ok */
+  SILC_SKR_ERROR              = 0x00000002, /* Generic error status */
+  SILC_SKR_ALREADY_EXIST      = 0x00000004, /* Key already exist */
+  SILC_SKR_NOT_FOUND          = 0x00000008, /* No keys were found */
+  SILC_SKR_NO_MEMORY          = 0x00000010, /* System out of memory */
+  SILC_SKR_UNSUPPORTED_TYPE   = 0x00000020, /* Unsupported PKCS type */
+} SilcSKRStatus;
+/***/
+
+/****f* silcskr/SilcSKRAPI/SilcSKRFindCallback
+ *
+ * SYNOPSIS
+ *
+ *    typedef void (*SilcSKRFindCallback)(SilcSKR skr, SilcSKRFind find,
+ *                                        SilcSKRStatus status,
+ *                                        SilcDList keys, void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Callback that is given as argument to silc_skr_find and other find
+ *    functions.  Returns the results of the finding.  If keys were found
+ *    the `keys' is non-NULL and receiver must free it with silc_dlist_uninit.
+ *    Each entry in the `keys' is SilcSKRKey context.  The list `keys' is
+ *    already at start so calling silc_dlist_start is not necessary when
+ *    traversing the list from the start.  If the `find' is non-NULL it must
+ *    be freed with silc_skr_find_free.
+ *
+ ***/
+typedef void (*SilcSKRFindCallback)(SilcSKR skr, SilcSKRFind find,
+                                   SilcSKRStatus status,
+                                   SilcDList keys, void *context);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_alloc
+ *
+ * SYNOPSIS
+ *
+ *    SilcSKR silc_skr_alloc(SilcSchedule scheduler);
+ *
+ * DESCRIPTION
+ *
+ *    Allocates key repository context.
+ *
+ ***/
+SilcSKR silc_skr_alloc(SilcSchedule scheduler);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_free
+ *
+ * SYNOPSIS
+ *
+ *    void silc_skr_free(SilcSKR skr);
+ *
+ * DESCRIPTION
+ *
+ *    Free's the key repository context `skr' and all resources in it.
+ *
+ ***/
+void silc_skr_free(SilcSKR skr);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_init
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_init(SilcSKR skr, SilcSchedule scheduler);
+ *
+ * DESCRIPTION
+ *
+ *    Initializes a pre-allocated SilcSKR context.  This function is
+ *    equivalent to silc_skr_alloc but takes pre-allocated context as
+ *    argument.  Returns FALSE if initialization failed.
+ *
+ ***/
+SilcBool silc_skr_init(SilcSKR skr, SilcSchedule scheduler);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_uninit
+ *
+ * SYNOPSIS
+ *
+ *    void silc_skr_uninit(SilcSKR skr);
+ *
+ * DESCRIPTION
+ *
+ *    Uninitializes a pre-allocated SilcSKR context.  Use this function if
+ *    you called silc_skr_init.
+ *
+ ***/
+void silc_skr_uninit(SilcSKR skr);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_add_public_key
+ *
+ * SYNOPSIS
+ *
+ *    SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
+ *                                          SilcPublicKey public_key,
+ *                                          SilcSKRKeyUsage usage,
+ *                                          void *key_context);
+ *
+ * DESCRIPTION
+ *
+ *    Add a public key to repository.  The repository will steal `public_key'
+ *    and caller must not free it.  The `key_context' is optional key specific
+ *    context that will be saved in the repository with the key, and can be
+ *    retrieved with the key.  Public key can be added only once to the
+ *    repository.  To add same key more than once to repository different
+ *    `key_context' must be used each time.
+ *
+ *    Returns SILC_SKR_OK if the key was added successfully, and error
+ *    status if key could not be added, or has been added already.
+ *
+ * EXAMPLE
+ *
+ *    // Add a key to repository
+ *    if (silc_skr_add_public_key(repository, public_key,
+ *                                SILC_SKR_USAGW_ANY, NULL) != SILC_SKR_OK)
+ *      goto error;
+ *
+ ***/
+SilcSKRStatus silc_skr_add_public_key(SilcSKR skr,
+                                     SilcPublicKey public_key,
+                                     SilcSKRKeyUsage usage,
+                                     void *key_context);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_add_public_key_simple
+ *
+ * SYNOPSIS
+ *
+ *    SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
+ *                                                 SilcPublicKey public_key,
+ *                                                 SilcSKRKeyUsage usage,
+ *                                                 void *key_context);
+ *
+ * DESCRIPTION
+ *
+ *    Same as silc_skr_add_public_key but adds only the public key, usage
+ *    bits and key context.  The key cannot be found with any other search
+ *    constraint except setting the public key, usage bits and/or key
+ *    context as search constraint.  This function can be used to add the
+ *    key with as little memory as possible to the repository, and makes
+ *    it a good way to cheaply store large amounts of public keys.
+ *
+ *    Returns SILC_SKR_OK if the key was added successfully, and error
+ *    status if key could not be added, or has been added already.
+ *
+ ***/
+SilcSKRStatus silc_skr_add_public_key_simple(SilcSKR skr,
+                                            SilcPublicKey public_key,
+                                            SilcSKRKeyUsage usage,
+                                            void *key_context);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_alloc
+ *
+ * SYNOPSIS
+ *
+ *    SilcSKRFind silc_skr_find_alloc(void);
+ *
+ * DESCRIPTION
+ *
+ *    Allocates SilcSKRFind context that will hold search constraints used
+ *    to find specific keys from the repository.  Caller must free the
+ *    context by calling silc_skr_find_free.
+ *
+ ***/
+SilcSKRFind silc_skr_find_alloc(void);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_free
+ *
+ * SYNOPSIS
+ *
+ *    void silc_skr_find_free(SilcSKRFind find);
+ *
+ * DESCRIPTION
+ *
+ *    Free's the search constraints context `find' and all resources in it.
+ *
+ ***/
+void silc_skr_find_free(SilcSKRFind find);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_add_pkcs_type
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_add_pkcs_type(SilcSKRFind find,
+ *                                         SilcPKCSType type);
+ *
+ * DESCRIPTION
+ *
+ *    Sets public key cryptosystem type as search constraint.  Will search
+ *    only for the specific type of key(s).
+ *
+ ***/
+SilcBool silc_skr_find_set_pkcs_type(SilcSKRFind find, SilcPKCSType type);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_set_username
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_set_username(SilcSKRFind find,
+ *                                        const char *username);
+ *
+ * DESCRIPTION
+ *
+ *    Sets username as search constraint.  This specific username must be
+ *    present in the key.
+ *
+ *    This may be used with SILC_PKCS_SILC PKCS type only.
+ *
+ ***/
+SilcBool silc_skr_find_set_username(SilcSKRFind find, const char *username);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_set_host
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_set_host(SilcSKRFind find,
+ *                                    const char *host);
+ *
+ * DESCRIPTION
+ *
+ *    Sets host as search constraint.  This specific host must be
+ *    present in the key.  The `host' may be a hostname or IP address.
+ *
+ *    This may be used with SILC_PKCS_SILC PKCS type only.
+ *
+ ***/
+SilcBool silc_skr_find_set_host(SilcSKRFind find, const char *host);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_set_realname
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_set_realname(SilcSKRFind find,
+ *                                        const char *realname);
+ *
+ * DESCRIPTION
+ *
+ *    Sets real name as search constraint.  This specific name must be
+ *    present in the key.
+ *
+ *    This may be used with SILC_PKCS_SILC PKCS type only.
+ *
+ ***/
+SilcBool silc_skr_find_set_realname(SilcSKRFind find, const char *realname);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_set_email
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_set_email(SilcSKRFind find,
+ *                                     const char *email);
+ *
+ * DESCRIPTION
+ *
+ *    Sets email address as search constraint.  This specific address must be
+ *    present in the key.
+ *
+ *    This may be used with SILC_PKCS_SILC PKCS type only.
+ *
+ ***/
+SilcBool silc_skr_find_set_email(SilcSKRFind find, const char *email);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_set_org
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_set_org(SilcSKRFind find,
+ *                                   const char *email);
+ *
+ * DESCRIPTION
+ *
+ *    Sets organization as search constraint.  This specific organization
+ *    must be present in the key.
+ *
+ *    This may be used with SILC_PKCS_SILC PKCS type only.
+ *
+ ***/
+SilcBool silc_skr_find_set_org(SilcSKRFind find, const char *org);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_set_country
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_set_country(SilcSKRFind find,
+ *                                       const char *email);
+ *
+ * DESCRIPTION
+ *
+ *    Sets country as search constraint.  This specific country must be
+ *    present in the key.
+ *
+ *    This may be used with SILC_PKCS_SILC PKCS type only.
+ *
+ ***/
+SilcBool silc_skr_find_set_country(SilcSKRFind find, const char *country);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_set_public_key
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_set_public_key(SilcSKRFind find,
+ *                                          SilcPublicKey public_key);
+ *
+ * DESCRIPTION
+ *
+ *    Sets public key as search constraint.  This specific key must be
+ *    present in the key.
+ *
+ ***/
+SilcBool silc_skr_find_set_public_key(SilcSKRFind find,
+                                     SilcPublicKey public_key);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_set_public_key
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_set_context(SilcSKRFind find, void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Sets public key specific context as search constraint.  This specific
+ *    context must be associated with the key.  This is the context that
+ *    was given as argument when adding the key to repository.
+ *
+ ***/
+SilcBool silc_skr_find_set_context(SilcSKRFind find, void *context);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_set_usage
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_skr_find_set_usage(SilcSKRFind find,
+ *                                     SilcSKRKeyUsage usage);
+ *
+ * DESCRIPTION
+ *
+ *    Sets key usage as search constraint.  At least one of the key usage
+ *    bits must be present in the key.  This search constraint cannot be
+ *    used alone to search keys.  At least one other search constraint
+ *    must also be used.
+ *
+ ***/
+SilcBool silc_skr_find_set_usage(SilcSKRFind find, SilcSKRKeyUsage usage);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find
+ *
+ * SYNOPSIS
+ *
+ *    SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find,
+ *                                     SilcSKRFindCallback callback,
+ *                                     void *callback_context);
+ *
+ * DESCRIPTION
+ *
+ *    Finds key(s) from key repository `skr' by the search constraints
+ *    `find'.  As the finding procedure may be asynchronous this returns
+ *    SilcAsyncOperation that may be used to control (like abort) the
+ *    operation.  The `callback' with `callback_context' will be called
+ *    to return found keys.  If this returns NULL, operation cannot be
+ *    controlled, however it is not an error.
+ *
+ ***/
+SilcAsyncOperation silc_skr_find(SilcSKR skr, SilcSKRFind find,
+                                SilcSKRFindCallback callback,
+                                void *callback_context);
+
+/****f* silcskr/SilcSKRAPI/silc_skr_find_silc
+ *
+ * SYNOPSIS
+ *
+ *    SilcAsyncOperation silc_skr_find_silc(SilcSKR skr,
+ *                                          SilcPublicKey public_key,
+ *                                          SilcSKRFindCallback callback,
+ *                                          void *callback_context);
+ *
+ * DESCRIPTION
+ *
+ *    A helper function that can be used to find specificly SILC style
+ *    public keys from the repository.  This returns found key(s) by
+ *    the `public_key'.  As the finding procedure may be asynchronous
+ *    this returns SilcAsyncOperation that may be used to control (like
+ *    abort) the operation.  The `callback' with `callback_context' will
+ *    be called to return found keys.  If this returns NULL, operation
+ *    cannot be controlled, however it is not an error.
+ *
+ ***/
+SilcAsyncOperation silc_skr_find_silc(SilcSKR skr,
+                                     SilcPublicKey public_key,
+                                     SilcSKRFindCallback callback,
+                                     void *callback_context);
+
+#include "silcskr_i.h"
+
+#endif /* SILCSKR_H */
diff --git a/lib/silcskr/silcskr_i.h b/lib/silcskr/silcskr_i.h
new file mode 100644 (file)
index 0000000..ef6ec71
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+
+  silcskr_i.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SILCSKR_I_H
+#define SILCSKR_I_H
+
+#ifndef SILCSKR_H
+#error "Do not include this header directly"
+#endif
+
+/* Internal representation of SilcSKRKey context. */
+typedef struct {
+  struct SilcSKRKeyStruct key;            /* Key data */
+  SilcInt32 refcnt;                       /* Reference counter */
+} *SilcSKRKeyInternal;
+
+/* Key Repository context */
+struct SilcSKRObject {
+  SilcSchedule scheduler;
+  SilcMutex lock;                        /* Repository lock */
+  SilcHashTable keys;                    /* All keys in repository */
+};
+
+/* Find context */
+struct SilcSKRFindStruct {
+  SilcHashTable constr;                           /* Search constraints */
+};
+
+#endif /* SILCSKR_I_H */
diff --git a/lib/silcskr/tests/Makefile.am b/lib/silcskr/tests/Makefile.am
new file mode 100644 (file)
index 0000000..580daad
--- /dev/null
@@ -0,0 +1,27 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@silcnet.org>
+#
+#  Copyright (C) 2005 Pekka Riikonen
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; version 2 of the License.
+#
+#  This program 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 General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+bin_PROGRAMS = test_silcskr
+
+test_silcskr_SOURCES = test_silcskr.c
+
+LIBS = $(SILC_COMMON_LIBS)
+LDADD = -L.. -L../.. -lsilc -lsilcskr
+
+include $(top_srcdir)/Makefile.defines.in
diff --git a/lib/silcskr/tests/test_silcskr.c b/lib/silcskr/tests/test_silcskr.c
new file mode 100644 (file)
index 0000000..4ee45cb
--- /dev/null
@@ -0,0 +1,138 @@
+/* SILC SKR tests */
+
+#include "silc.h"
+#include "silcskr.h"
+
+SilcBool found = TRUE;
+
+static void skr_found(SilcSKR skr, SilcSKRFind find, SilcSKRStatus status,
+                     SilcDList results, void *context)
+{
+  SilcSKRKey key;
+
+  SILC_LOG_DEBUG(("Result status %d", status));
+  if (status & SILC_SKR_OK) {
+    SILC_LOG_DEBUG(("Found %d keys", silc_dlist_count(results)));
+
+    while ((key = silc_dlist_get(results)) != SILC_LIST_END)
+      SILC_LOG_DEBUG(("Key: %s", ((SilcPublicKey)key->key)->identifier));
+
+    silc_dlist_uninit(results);
+    found = TRUE;
+  } else
+    found = FALSE;
+}
+
+int main(int argc, char **argv)
+{
+  SilcBool success = FALSE;
+  SilcSchedule schedule;
+  SilcSKR skr;
+  SilcSKRFind find;
+  SilcPublicKey pk;
+
+  if (argc > 1 && !strcmp(argv[1], "-d")) {
+    silc_log_debug(TRUE);
+    silc_log_debug_hexdump(TRUE);
+    silc_log_set_debug_string("*skr*");
+  }
+
+  SILC_LOG_DEBUG(("Allocating scheduler"));
+  schedule = silc_schedule_init(0, NULL);
+
+  SILC_LOG_DEBUG(("Allocating SKR"));
+  skr = silc_skr_alloc(schedule);
+  if (!skr)
+    goto err;
+
+  SILC_LOG_DEBUG(("Adding public key to SKR"));
+  pk = silc_calloc(1, sizeof(*pk));
+  pk->len = 1;
+  pk->pk_type = SILC_PKCS_SILC;
+  pk->name = strdup("rsa");
+  pk->pk = strdup("  ");
+  pk->pk_len = 2;
+  pk->identifier = silc_pkcs_encode_identifier("foo", "foo.com",
+                                              "Foo T. Bar", "foo@foo.com",
+                                              "ORG", "FI");
+  silc_skr_add_public_key(skr, pk, 0, NULL);
+
+  SILC_LOG_DEBUG(("Adding public key to SKR"));
+  pk = silc_calloc(1, sizeof(*pk));
+  pk->len = 1;
+  pk->pk_type = SILC_PKCS_SILC;
+  pk->name = strdup("rsa");
+  pk->pk = strdup("  ");
+  pk->pk_len = 2;
+  pk->identifier = silc_pkcs_encode_identifier("bar", "bar.com",
+                                              "Bar T. Bar", "bar@foo.com",
+                                              "ORG", "FI");
+  silc_skr_add_public_key(skr, pk, SILC_SKR_USAGE_IDENTIFICATION |
+                         SILC_SKR_USAGE_AUTH, NULL);
+
+  SILC_LOG_DEBUG(("Attempting to add key twice"));
+  if (silc_skr_add_public_key(skr, pk, 0, NULL) == SILC_SKR_OK) {
+    SILC_LOG_DEBUG(("Adding key twice not detected"));
+    goto err;
+  }
+
+  SILC_LOG_DEBUG(("Finding public key by email"));
+  find = silc_skr_find_alloc();
+  silc_skr_find_set_email(find, "foo@foo.com");
+  silc_skr_find(skr, find, skr_found, NULL);
+  silc_skr_find_free(find);
+  if (!found)
+    goto err;
+
+  SILC_LOG_DEBUG(("Finding public key by country"));
+  find = silc_skr_find_alloc();
+  silc_skr_find_set_country(find, "FI");
+  silc_skr_find(skr, find, skr_found, NULL);
+  silc_skr_find_free(find);
+  if (!found)
+    goto err;
+
+  SILC_LOG_DEBUG(("Finding public key by country, ORG and hostname"));
+  find = silc_skr_find_alloc();
+  silc_skr_find_set_country(find, "FI");
+  silc_skr_find_set_org(find, "ORG");
+  silc_skr_find_set_host(find, "foo.com");
+  silc_skr_find(skr, find, skr_found, NULL);
+  silc_skr_find_free(find);
+  if (!found)
+    goto err;
+
+  SILC_LOG_DEBUG(("Finding public key by SILC public key"));
+  silc_skr_find_silc(skr, pk, skr_found, NULL);
+  if (!found)
+    goto err;
+
+  SILC_LOG_DEBUG(("Finding public key by country and usage (must not find)"));
+  find = silc_skr_find_alloc();
+  silc_skr_find_set_country(find, "FI");
+  silc_skr_find_set_usage(find, SILC_SKR_USAGE_ENC);
+  silc_skr_find(skr, find, skr_found, NULL);
+  silc_skr_find_free(find);
+  if (found)
+    goto err;
+
+  SILC_LOG_DEBUG(("Finding public key by country and usage"));
+  find = silc_skr_find_alloc();
+  silc_skr_find_set_country(find, "FI");
+  silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
+  silc_skr_find(skr, find, skr_found, NULL);
+  silc_skr_find_free(find);
+  if (!found)
+    goto err;
+
+  silc_skr_free(skr);
+  silc_schedule_uninit(schedule);
+
+  success = TRUE;
+
+ err:
+  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
+  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+  return success;
+}
index 6e825ea75bc30f405178389eddb7e1687a92069e..2e1cef0cb7f6818518b419905b16fea58b6236a0 100644 (file)
@@ -19,7 +19,7 @@
 /* I used Apache's APR code as a reference here. */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifdef SILC_THREADS
 
index 616649df6328adbbd9c08243488b2fe5d3c3ff53..dc4ed7096504a94568da0bf6b0f3086461ddac29 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Maybe works, or maybe not */
 #include "../unix/silcunixnet.c"
index f3ad4cae3dcb0c941ce61f2a290527b9290f1f59..875442cb0a9da313371e79ac429a790361dce553 100644 (file)
@@ -22,7 +22,7 @@
 #ifdef SILC_BEOS_BONE
 #include "../unix/silcunixsockconn.c"
 #else
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Writes data from encrypted buffer to the socket connection. If the
    data cannot be written at once, it will be written later with a timeout. 
index 909a3ac726a29b0f9a8cb601a5e789ede5c17c6d..eb411412f6b0bd52ae0c0a7c2e74d3f21f4e85a9 100644 (file)
@@ -23,7 +23,7 @@
    since the silc_thread_self() causes that BeOS and OS/2 is hard to
    do to support this SilcThread API */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifdef SILC_THREADS
 
index 3e8582d7df62f0878f8c028622e662c7e695d319..6af5811f061387375c74ef10cb3bd4d86ee897f1 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Inspects the `string' for wildcards and returns regex string that can
    be used by the GNU regex library. A comma (`,') in the `string' means
index ba5e36f094863b27548ee6ba1b0dfb7644b23423..38acee0ceb89b70481fa58c62bdee03709a79ad3 100644 (file)
@@ -19,7 +19,7 @@
 /* I used Apache's APR code as a reference here. */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifdef SILC_THREADS
 
index 9ec496d18277fc4da6dbf36d5bb22a5aca237f98..050385a688aa976be2224ea2e26bfe7ae4921da6 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcnet.h"
 
 /* XXX TODO */
index fc60566bc89b133452efac1a2845e4b9fa1bd5bf..4cec5864644a3271c6da4261a25cb5097cf1e91b 100644 (file)
@@ -20,7 +20,7 @@
 
 /* XXX TODO */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcschedule_i.h"
 
 /* Calls normal select() system call. */
index dccc2abc85cce79e6e7812cef2d92c6d1f89b9ea..d551c0b7cf159650a0bc0ac8404fb10ae8527807 100644 (file)
@@ -20,7 +20,7 @@
 
 /* XXX TODO */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Writes data from encrypted buffer to the socket connection. If the
    data cannot be written at once, it will be written later with a timeout. 
index eb2093672520ffdea9f51f3a27bd79a439401c18..eb18dcde9cda6c4b3224e66d70848a709deebc2f 100644 (file)
@@ -19,7 +19,7 @@
 /* I used Apache's APR code as a reference here. */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* XXX This leaks memory. Perhaps the SilcThread API should be changed
    since the silc_thread_self() causes that BeOS and OS/2 is hard to
index 4a5877dd8ee737f1d734c80de753775cddaf1a22..7910fd78642d62a10c4f415f27b63ab0cd5df9e0 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 char *silc_string_regexify(const char *string)
 {
index 98ecddaf4501df378b3f53569c6a1c7a8b0a2213..d1d6739ff751b56e8f8173e93273d18a21f9b1cb 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 static char *silc_create_pk_identifier(void)
 {
index d1552cae52d67acda487c199bcec953b85a7d7ef..3e7294d778018c0fd7312f0cd0bee287f2b51204 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Halts async operation */
 
@@ -83,9 +83,9 @@ SilcAsyncOperation silc_async_alloc(SilcAsyncOperationAbort abort_cb,
 /* Creates new async operation */
 
 SilcBool silc_async_init(SilcAsyncOperation op,
-                    SilcAsyncOperationAbort abort_cb,
-                    SilcAsyncOperationPause pause_cb,
-                    void *context)
+                        SilcAsyncOperationAbort abort_cb,
+                        SilcAsyncOperationPause pause_cb,
+                        void *context)
 {
   assert(abort_cb);
   op->abort_cb = abort_cb;
index 650419a836646fac93a9cbf448817373a390ae2c..773dd059bee5237ca571f19ca6e19409c807fecf 100644 (file)
@@ -117,8 +117,8 @@ typedef void (*SilcAsyncOperationAbort)(SilcAsyncOperation op,
  *
  ***/
 typedef SilcBool (*SilcAsyncOperationPause)(SilcAsyncOperation op,
-                                        SilcBool pause_operation,
-                                       void *context);
+                                           SilcBool pause_operation,
+                                           void *context);
 
 /* Upper layer functions for managing asynchronous operations.  Layer
    that has received SilcAsyncOperation context can control the async
@@ -260,9 +260,9 @@ SilcAsyncOperation silc_async_alloc(SilcAsyncOperationAbort abort_cb,
  *
  ***/
 SilcBool silc_async_init(SilcAsyncOperation op,
-                    SilcAsyncOperationAbort abort_cb,
-                    SilcAsyncOperationPause pause_cb,
-                    void *context);
+                        SilcAsyncOperationAbort abort_cb,
+                        SilcAsyncOperationPause pause_cb,
+                        void *context);
 
 /****f* silcutil/SilcAsyncOperationAPI/silc_async_free
  *
index bd091a54a8e3059ce275c8a367a10abe86d18638..3c96f862ca1338f7bc93888a60407c170ff3adc2 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Macros to check whether there is enough free space to add the
    required amount of data. For unformatting this means that there must
index 697aae14adf39ec9a89bf10979757bda538d2016..93e27d2d3560ac655a6300e1c34662e444124ef6 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* limit debug logging verbosity */
 #if 0
index 6966f304a0719faec9c18a5090a0b4971b111c1c..d205ede0a9a1a55e91e05024edd097ff441a0efa 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2000 - 2003 Pekka Riikonen
+  Copyright (C) 2000 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -56,6 +56,8 @@
  */
 typedef struct SilcDListStruct {
   SilcList list;
+  void *current;
+  void *prev;
 } *SilcDList;
 /***/
 
@@ -88,6 +90,7 @@ SilcDList silc_dlist_init(void)
   list = (SilcDList)silc_malloc(sizeof(*list));
   if (!list)
     return NULL;
+  list->current = list->prev = NULL;
   silc_list_init_prev(list->list, struct SilcDListEntryStruct, next, prev);
 
   return list;
@@ -158,6 +161,7 @@ static inline
 void silc_dlist_start(SilcDList list)
 {
   silc_list_start(list->list);
+  list->current = list->prev = NULL;
 }
 
 /****f* silcutil/SilcDListAPI/silc_dlist_end
@@ -178,6 +182,7 @@ static inline
 void silc_dlist_end(SilcDList list)
 {
   silc_list_end(list->list);
+  list->current = list->prev = NULL;
 }
 
 /****f* silcutil/SilcDListAPI/silc_dlist_add
@@ -185,7 +190,7 @@ void silc_dlist_end(SilcDList list)
  * SYNOPSIS
  *
  *    static inline
- *    void silc_dlist_add(SilcDList list, void *context);
+ *    SilcBool silc_dlist_add(SilcDList list, void *context);
  *
  * DESCRIPTION
  *
@@ -195,13 +200,40 @@ void silc_dlist_end(SilcDList list)
  ***/
 
 static inline
-void silc_dlist_add(SilcDList list, void *context)
+SilcBool silc_dlist_add(SilcDList list, void *context)
 {
   SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
   if (!e)
-    return;
+    return FALSE;
   e->context = context;
   silc_list_add(list->list, e);
+  return TRUE;
+}
+
+/****f* silcutil/SilcDList/silc_dlist_insert
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcBool silc_dlist_insert(SilcDList list, void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Insert new entry to the list between current and previous entry.
+ *    If list is at the start this adds the entry at head of the list.
+ *    Use silc_dlist_add to add at the end of the list.
+ *
+ ***/
+
+static inline
+SilcBool silc_dlist_insert(SilcDList list, void *context)
+{
+  SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
+  if (!e)
+    return FALSE;
+  e->context = context;
+  silc_list_insert(list->list, list->prev, e);
+  return TRUE;
 }
 
 /****f* silcutil/SilcDListAPI/silc_dlist_del
@@ -229,6 +261,10 @@ void silc_dlist_del(SilcDList list, void *context)
 #if defined(SILC_DEBUG)
       memset(e, 'F', sizeof(*e));
 #endif
+      if (list->current == e)
+       list->current = NULL;
+      if (list->prev == e)
+       list->prev = NULL;
       silc_free(e);
       break;
     }
@@ -263,7 +299,9 @@ void silc_dlist_del(SilcDList list, void *context)
 static inline
 void *silc_dlist_get(SilcDList list)
 {
-  SilcDListEntry e = (SilcDListEntry)silc_list_get(list->list);
+  SilcDListEntry e;
+  list->prev = list->current;
+  list->current = e = (SilcDListEntry)silc_list_get(list->list);
   if (e != SILC_LIST_END)
     return e->context;
   return SILC_LIST_END;
index d707e59a326029d073e220b62a4f11dd1c8fd97c..db9bd9d724185d0396b454b5857d301eb7790c84 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #define SILC_IS_FD_STREAM(s) (s->ops == &silc_fd_stream_ops)
 
@@ -59,17 +59,16 @@ SILC_TASK_CALLBACK(silc_fd_stream_io)
 
 /* Create file descriptor stream */
 
-SilcStream silc_fd_stream_create(int fd, SilcSchedule schedule)
+SilcStream silc_fd_stream_create(int fd)
 {
   if (fd < 1)
     return NULL;
-  return silc_fd_stream_create2(fd, 0, schedule);
+  return silc_fd_stream_create2(fd, 0);
 }
 
 /* Create stream with two file descriptors */
 
-SilcStream silc_fd_stream_create2(int read_fd, int write_fd,
-                                 SilcSchedule schedule)
+SilcStream silc_fd_stream_create2(int read_fd, int write_fd)
 {
   SilcFDStream stream;
 
@@ -83,31 +82,16 @@ SilcStream silc_fd_stream_create2(int read_fd, int write_fd,
   SILC_LOG_DEBUG(("Creating new fd stream %p", stream));
 
   stream->ops = &silc_fd_stream_ops;
-  stream->schedule = schedule;
   stream->fd1 = read_fd;
   stream->fd2 = write_fd;
 
-  /* Schedule the file descriptors */
-  if (write_fd > 0) {
-    silc_schedule_task_add_fd(schedule, write_fd, silc_fd_stream_io, stream);
-    silc_file_set_nonblock(write_fd);
-  }
-  if (read_fd > 0) {
-    silc_schedule_task_add_fd(schedule, read_fd, silc_fd_stream_io, stream);
-    silc_schedule_set_listen_fd(schedule, read_fd, SILC_TASK_READ, FALSE);
-    silc_file_set_nonblock(read_fd);
-    if (write_fd < 1)
-      stream->fd2 = stream->fd1;
-  }
-
   return stream;
 }
 
 /* Create by opening file */
 
 SilcStream silc_fd_stream_file(const char *filename,
-                              SilcBool reading, SilcBool writing,
-                              SilcSchedule schedule)
+                              SilcBool reading, SilcBool writing)
 {
   int fd, flags = 0;
 
@@ -117,20 +101,21 @@ SilcStream silc_fd_stream_file(const char *filename,
   if (reading)
     flags |= O_RDONLY;
   if (writing)
-    flags |= O_WRONLY;
+    flags |= O_CREAT | O_WRONLY;
   if (reading && writing)
-    flags |= O_RDWR;
+    flags |= O_CREAT | O_RDWR;
 
   fd = silc_file_open(filename, flags);
   if (fd < 0)
     return NULL;
 
-  return silc_fd_stream_create(fd, schedule);
+  return silc_fd_stream_create(fd);
 }
 
 /* Return fds */
 
-SilcBool silc_fd_stream_get_info(SilcStream stream, int *read_fd, int *write_fd)
+SilcBool silc_fd_stream_get_info(SilcStream stream, int *read_fd,
+                                int *write_fd)
 {
   SilcFDStream fd_stream = stream;
 
@@ -167,6 +152,8 @@ int silc_fd_stream_read(SilcStream stream, unsigned char *buf,
 
   if (!SILC_IS_FD_STREAM(fd_stream))
     return -2;
+  if (!fd_stream->notifier)
+    return -2;
 
   SILC_LOG_DEBUG(("Reading data from fd %d", fd_stream->fd1));
 
@@ -203,6 +190,8 @@ int silc_fd_stream_write(SilcStream stream, const unsigned char *data,
 
   if (!SILC_IS_FD_STREAM(fd_stream))
     return -2;
+  if (!fd_stream->notifier)
+    return -2;
 
   SILC_LOG_DEBUG(("Writing data to fd %d", fd_stream->fd2));
 
@@ -270,6 +259,7 @@ void silc_fd_stream_destroy(SilcStream stream)
 /* Sets stream notification callback for the stream */
 
 void silc_fd_stream_notifier(SilcStream stream,
+                            SilcSchedule schedule,
                             SilcStreamNotifier callback,
                             void *context)
 {
@@ -282,6 +272,40 @@ void silc_fd_stream_notifier(SilcStream stream,
 
   fd_stream->notifier = callback;
   fd_stream->notifier_context = context;
+  fd_stream->schedule = schedule;
+
+  /* Schedule the file descriptors */
+  if (schedule) {
+    if (fd_stream->fd2 > 0) {
+      silc_schedule_task_add_fd(schedule, fd_stream->fd2,
+                               silc_fd_stream_io, stream);
+      silc_file_set_nonblock(fd_stream->fd2);
+    }
+    if (fd_stream->fd1 > 0) {
+      silc_schedule_task_add_fd(schedule, fd_stream->fd1,
+                               silc_fd_stream_io, stream);
+      silc_schedule_set_listen_fd(schedule, fd_stream->fd1,
+                                 SILC_TASK_READ, FALSE);
+      silc_file_set_nonblock(fd_stream->fd1);;
+      if (fd_stream->fd2 < 1)
+       fd_stream->fd2 = fd_stream->fd1;
+    }
+  } else {
+    silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1);
+    silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2);
+  }
+}
+
+/* Return schedule */
+
+SilcSchedule silc_fd_stream_get_schedule(SilcStream stream)
+{
+  SilcFDStream fd_stream = stream;
+
+  if (!SILC_IS_FD_STREAM(fd_stream))
+    return NULL;
+
+  return fd_stream->schedule;
 }
 
 /* File descriptor stream operations */
@@ -292,4 +316,5 @@ const SilcStreamOps silc_fd_stream_ops =
   silc_fd_stream_close,
   silc_fd_stream_destroy,
   silc_fd_stream_notifier,
+  silc_fd_stream_get_schedule
 };
index fc1a4c8f243dd4fd529250d918cc4ee3f18213ef..0b09fd3a520ed8f148d6cf56b7d09dcdca91057e 100644 (file)
@@ -38,7 +38,7 @@
  *
  * SYNOPSIS
  *
- *    SilcStream silc_fd_stream_create(int fd, SilcSchedule schedule);
+ *    SilcStream silc_fd_stream_create(int fd);
  *
  * DESCRIPTION
  *
  *    by `fd'.  The stream is closed with the silc_stream_close and destroyed
  *    with the silc_stream_destroy.
  *
+ *    The silc_stream_set_notifier must be called in order to be able to read
+ *    from and write to this file descriptor stream.
+ *
  ***/
-SilcStream silc_fd_stream_create(int fd, SilcSchedule schedule);
+SilcStream silc_fd_stream_create(int fd);
 
 /****f* silcutil/SilcFDStreamAPI/silc_fd_stream_create2
  *
  * SYNOPSIS
  *
- *    SilcStream silc_fd_stream_create2(int read_fd, int write_fd,
- *                                      SilcSchedule schedule);
+ *    SilcStream silc_fd_stream_create2(int read_fd, int write_fd);
  *
  * DESCRIPTION
  *
@@ -63,16 +65,18 @@ SilcStream silc_fd_stream_create(int fd, SilcSchedule schedule);
  *    and `write_fd' opened for writing.  The stream is closed with the
  *    silc_stream_close and destroyed with the silc_stream_destroy.
  *
+ *    The silc_stream_set_notifier must be called in order to be able to read
+ *    from and write to this file descriptor stream.
+ *
  ***/
-SilcStream silc_fd_stream_create2(int read_fd, int write_fd,
-                                 SilcSchedule schedule);
+SilcStream silc_fd_stream_create2(int read_fd, int write_fd);
 
 /****f* silcutil/SilcFDStreamAPI/silc_fd_stream_file
  *
  * SYNOPSIS
  *
  *    SilcStream silc_fd_stream_file(const char *filename, SilcBool reading,
- *                                   SilcBool writing, SilcSchedule schedule);
+ *                                   SilcBool writing);
  *
  * DESCRIPTION
  *
@@ -81,9 +85,12 @@ SilcStream silc_fd_stream_create2(int read_fd, int write_fd,
  *    opened for reading.  If the `writing' is TRUE the file is opened
  *    for writing.
  *
+ *    The silc_stream_set_notifier must be called in order to be able to read
+ *    from and write to this file descriptor stream.
+ *
  ***/
-SilcStream silc_fd_stream_file(const char *filename, SilcBool reading, 
-                              SilcBool writing, SilcSchedule schedule);
+SilcStream silc_fd_stream_file(const char *filename, SilcBool reading,
+                              SilcBool writing);
 
 /****f* silcutil/SilcFDStreamAPI/silc_fd_stream_get_info
  *
@@ -99,7 +106,8 @@ SilcStream silc_fd_stream_file(const char *filename, SilcBool reading,
  *    function.
  *
  ***/
-SilcBool silc_fd_stream_get_info(SilcStream stream, int *read_fd, int *write_fd);
+SilcBool silc_fd_stream_get_info(SilcStream stream,
+                                int *read_fd, int *write_fd);
 
 /****f* silcutil/SilcFDStreamAPI/silc_fd_stream_get_error
  *
index 718cb6f1fb6f77dd5fe50e1dea684b49f28bc1b9..30b2a5e5ce2001df916e0a0ebb7b8f38a309af49 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Opens a file indicated by the filename `filename' with flags indicated
    by the `flags'. */
index 4d09205db4e9043e5eac1b0679d5c57e2b156701..dcefb09cef98b208d93f6896a094c3fd57b5945c 100644 (file)
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 SILC_TASK_CALLBACK(silc_fsm_run);
 SILC_TASK_CALLBACK(silc_fsm_finish);
 SILC_TASK_CALLBACK(silc_fsm_sema_timedout);
 SILC_TASK_CALLBACK(silc_fsm_start_real_thread);
 static void *silc_fsm_thread(void *context);
+static void silc_fsm_thread_termination_post(SilcFSMSema sema);
+static void silc_fsm_sema_ref(SilcFSMSema sema);
+static void silc_fsm_sema_unref(SilcFSMSema sema);
 
 /* Allocate FSM */
 
@@ -50,15 +53,16 @@ SilcFSM silc_fsm_alloc(void *fsm_context,
 /* Initialize FSM */
 
 SilcBool silc_fsm_init(SilcFSM fsm,
-                  void *fsm_context,
-                   SilcFSMDestructor destructor,
-                   void *destructor_context,
-                   SilcSchedule schedule)
+                      void *fsm_context,
+                      SilcFSMDestructor destructor,
+                      void *destructor_context,
+                      SilcSchedule schedule)
 {
   if (!schedule)
     return FALSE;
 
   fsm->fsm_context = fsm_context;
+  fsm->state_context = NULL;
   fsm->destructor = destructor;
   fsm->destructor_context = destructor_context;
   fsm->schedule = schedule;
@@ -84,18 +88,14 @@ SilcFSMThread silc_fsm_thread_alloc(SilcFSM fsm,
   if (!thread)
     return NULL;
 
-  if (!silc_fsm_thread_init(thread, fsm, thread_context, destructor,
-                           destructor_context, real_thread)) {
-    silc_free(thread);
-    return NULL;
-  }
-
+  silc_fsm_thread_init(thread, fsm, thread_context, destructor,
+                      destructor_context, real_thread);
   return thread;
 }
 
 /* Initialize FSM thread.  Internally machine and thread use same context. */
 
-SilcBool silc_fsm_thread_init(SilcFSMThread thread,
+void silc_fsm_thread_init(SilcFSMThread thread,
                          SilcFSM fsm,
                          void *thread_context,
                          SilcFSMThreadDestructor destructor,
@@ -110,6 +110,7 @@ SilcBool silc_fsm_thread_init(SilcFSMThread thread,
 #endif /* SILC_DEBUG */
 
   thread->fsm_context = thread_context;
+  thread->state_context = NULL;
   thread->destructor = (SilcFSMDestructor)destructor;
   thread->destructor_context = destructor_context;
   thread->schedule = fsm->schedule;
@@ -125,8 +126,6 @@ SilcBool silc_fsm_thread_init(SilcFSMThread thread,
   if (real_thread && !fsm->u.m.lock)
     if (!silc_mutex_alloc(&fsm->u.m.lock))
       thread->real_thread = FALSE;
-
-  return TRUE;
 }
 
 /* FSM is destroyed through scheduler to make sure that all dying
@@ -203,13 +202,8 @@ SILC_TASK_CALLBACK(silc_fsm_start_real_thread)
 
   SILC_LOG_DEBUG(("Could not create real thread, using normal FSM thread"));
 
-  f->real_thread = FALSE;
-  if (f->u.m.lock) {
-    silc_mutex_free(f->u.m.lock);
-    f->u.m.lock = NULL;
-  }
-
   /* Normal FSM operation */
+  f->real_thread = FALSE;
   silc_fsm_continue_sync(f);
 }
 
@@ -225,7 +219,7 @@ void silc_fsm_start(void *fsm, SilcFSMStateCallback start_state)
   f->next_state = start_state;
   f->synchronous = FALSE;
 
-  /* Start real threads through scheduler */
+  /* Start real thread through scheduler */
   if (f->thread && f->real_thread) {
     silc_schedule_task_add_timeout(f->schedule, silc_fsm_start_real_thread,
                                   f, 0, 1);
@@ -248,7 +242,7 @@ void silc_fsm_start_sync(void *fsm, SilcFSMStateCallback start_state)
   f->next_state = start_state;
   f->synchronous = TRUE;
 
-  /* Start real threads through scheduler */
+  /* Start real thread directly */
   if (f->thread && f->real_thread) {
     silc_fsm_start_real_thread(f->schedule,
                               silc_schedule_get_context(f->schedule),
@@ -275,6 +269,8 @@ void silc_fsm_next_later(void *fsm, SilcFSMStateCallback next_state,
 {
   SilcFSM f = fsm;
   f->next_state = next_state;
+  if (!seconds && !useconds)
+    return;
   silc_schedule_task_add_timeout(f->schedule, silc_fsm_run, f,
                                 seconds, useconds);
 }
@@ -303,6 +299,22 @@ SilcSchedule silc_fsm_get_schedule(void *fsm)
   return f->schedule;
 }
 
+/* Return thread's machine */
+
+SilcFSM silc_fsm_get_machine(SilcFSMThread thread)
+{
+  assert(thread->thread);
+  return (SilcFSM)thread->u.t.fsm;
+}
+
+/* Set context */
+
+void silc_fsm_set_context(void *fsm, void *fsm_context)
+{
+  SilcFSM f = fsm;
+  f->fsm_context = fsm_context;
+}
+
 /* Get context */
 
 void *silc_fsm_get_context(void *fsm)
@@ -311,12 +323,20 @@ void *silc_fsm_get_context(void *fsm)
   return f->fsm_context;
 }
 
-/* Set context */
+/* Set state context */
 
-void silc_fsm_set_context(void *fsm, void *fsm_context)
+void silc_fsm_set_state_context(void *fsm, void *state_context)
 {
   SilcFSM f = fsm;
-  f->fsm_context = fsm_context;
+  f->state_context = state_context;
+}
+
+/* Get state context */
+
+void *silc_fsm_get_state_context(void *fsm)
+{
+  SilcFSM f = fsm;
+  return f->state_context;
 }
 
 /* Wait for thread to terminate */
@@ -343,16 +363,12 @@ SILC_TASK_CALLBACK(silc_fsm_run)
 
   SILC_LOG_DEBUG(("Running %s %p", fsm->thread ? "thread" : "FSM", fsm));
 
-  /* Run the state */
-  status = fsm->next_state(fsm, fsm->fsm_context);
+  /* Run the states */
+  do
+    status = fsm->next_state(fsm, fsm->fsm_context, fsm->state_context);
+  while (status == SILC_FSM_CONTINUE);
 
   switch (status) {
-  case SILC_FSM_CONTINUE:
-    /* Synchronously move to next state */
-    SILC_LOG_DEBUG(("State continue %p", fsm));
-    silc_fsm_run(schedule, app_context, type, fd, context);
-    break;
-
   case SILC_FSM_WAIT:
     /* The machine is in hold */
     SILC_LOG_DEBUG(("State wait %p", fsm));
@@ -383,6 +399,9 @@ SILC_TASK_CALLBACK(silc_fsm_run)
       silc_schedule_task_add_timeout(fsm->schedule, silc_fsm_finish,
                                     fsm, 0, 1);
     break;
+
+  default:
+    break;
   }
 }
 
@@ -400,8 +419,7 @@ SILC_TASK_CALLBACK(silc_fsm_finish)
   if (fsm->thread) {
     /* This is thread, send signal */
     if (fsm->u.t.sema) {
-      silc_fsm_sema_post(fsm->u.t.sema);
-      silc_fsm_sema_wait(fsm->u.t.sema, fsm->u.t.sema->fsm);
+      silc_fsm_thread_termination_post(fsm->u.t.sema);
       silc_fsm_sema_free(fsm->u.t.sema);
       fsm->u.t.sema = NULL;
     }
@@ -421,20 +439,6 @@ SILC_TASK_CALLBACK(silc_fsm_finish)
   }
 }
 
-/* Signalled, semaphore */
-
-static void silc_fsm_signal(SilcFSM fsm)
-{
-  SILC_LOG_DEBUG(("Signalled %s %p", fsm->thread ? "thread" : "FSM", fsm));
-
-  /* Continue */
-  silc_fsm_continue(fsm);
-
-  /* Wakeup the destination's scheduler in case the signaller is a
-     real thread. */
-  silc_schedule_wakeup(fsm->schedule);
-}
-
 /* Allocate FSM semaphore */
 
 SilcFSMSema silc_fsm_sema_alloc(SilcFSM fsm, SilcUInt32 value)
@@ -446,6 +450,7 @@ SilcFSMSema silc_fsm_sema_alloc(SilcFSM fsm, SilcUInt32 value)
     return NULL;
 
   silc_fsm_sema_init(sema, fsm, value);
+  sema->allocated = TRUE;
 
   return sema;
 }
@@ -458,7 +463,9 @@ void silc_fsm_sema_init(SilcFSMSema sema, SilcFSM fsm, SilcUInt32 value)
 #if defined(SILC_DEBUG)
   assert(!fsm->thread);
 #endif /* SILC_DEBUG */
+  memset(sema, 0, sizeof(*sema));
   sema->fsm = fsm;
+  sema->refcnt = 0;
   silc_list_init(sema->waiters, struct SilcFSMObject, next);
   sema->value = value;
 }
@@ -467,12 +474,30 @@ void silc_fsm_sema_init(SilcFSMSema sema, SilcFSM fsm, SilcUInt32 value)
 
 void silc_fsm_sema_free(SilcFSMSema sema)
 {
+  if (sema->refcnt > 0)
+    return;
 #if defined(SILC_DEBUG)
   assert(silc_list_count(sema->waiters) == 0);
 #endif /* SILC_DEBUG */
   silc_free(sema);
 }
 
+/* Reference semaphore */
+
+static void silc_fsm_sema_ref(SilcFSMSema sema)
+{
+  sema->refcnt++;
+}
+
+/* Unreference semaphore */
+
+static void silc_fsm_sema_unref(SilcFSMSema sema)
+{
+  sema->refcnt--;
+  if (sema->refcnt == 0 && sema->allocated)
+    silc_fsm_sema_free(sema);
+}
+
 /* Wait until semaphore is non-zero. */
 
 SilcUInt32 silc_fsm_sema_wait(SilcFSMSema sema, void *fsm)
@@ -509,17 +534,26 @@ SilcUInt32 silc_fsm_sema_wait(SilcFSMSema sema, void *fsm)
 /* Wait util semaphore is non-zero, or timeout occurs. */
 
 SilcUInt32 silc_fsm_sema_timedwait(SilcFSMSema sema, void *fsm,
-                                  SilcUInt32 seconds, SilcUInt32 useconds)
+                                  SilcUInt32 seconds, SilcUInt32 useconds,
+                                  SilcBool *ret_to)
 {
+  SilcMutex lock = sema->fsm->u.m.lock;
   SilcFSM f = fsm;
   SilcUInt32 value;
 
+  silc_mutex_lock(lock);
+
   if (f->sema_timedout) {
     SILC_LOG_DEBUG(("Semaphore was timedout"));
     f->sema_timedout = FALSE;
+    if (ret_to)
+      *ret_to = TRUE;
+    silc_mutex_unlock(lock);
     return 1;
   }
 
+  silc_mutex_unlock(lock);
+
   value = silc_fsm_sema_wait(sema, fsm);
   if (!value) {
     silc_schedule_task_add_timeout(f->schedule, silc_fsm_sema_timedout,
@@ -527,6 +561,9 @@ SilcUInt32 silc_fsm_sema_timedwait(SilcFSMSema sema, void *fsm,
     f->sema = sema;
   }
 
+  if (ret_to)
+    *ret_to = FALSE;
+
   return value;
 }
 
@@ -542,13 +579,45 @@ SILC_TASK_CALLBACK(silc_fsm_sema_timedout)
   /* Remove the waiter from the semaphore */
   silc_mutex_lock(lock);
   silc_list_del(fsm->sema->waiters, fsm);
+
+  /* Continue */
+  if (fsm->sema) {
+    silc_fsm_continue(fsm);
+    fsm->sema_timedout = TRUE;
+    fsm->sema = NULL;
+  }
+
   silc_mutex_unlock(lock);
+}
 
-  fsm->sema = NULL;
-  fsm->sema_timedout = TRUE;
+/* Signalled, semaphore */
 
-  /* Continue */
-  silc_fsm_continue(fsm);
+SILC_TASK_CALLBACK(silc_fsm_signal)
+{
+  SilcFSMSemaPost p = context;
+  SilcMutex lock = p->sema->fsm->u.m.lock;
+
+  /* If the semaphore value has went to zero while we've been waiting this
+     callback, sempahore has been been signalled already.  It can happen
+     when using real threads because the FSM may not be waiting state when
+     the sempahore is posted. */
+  silc_mutex_lock(lock);
+  if (!p->sema->value) {
+    silc_mutex_unlock(lock);
+    silc_fsm_sema_unref(p->sema);
+    silc_free(p);
+    return;
+  }
+  silc_mutex_unlock(lock);
+
+  SILC_LOG_DEBUG(("Signalled %s %p", p->fsm->thread ? "thread" : "FSM",
+                 p->fsm));
+
+  /* Signal */
+  silc_fsm_continue_sync(p->fsm);
+
+  silc_fsm_sema_unref(p->sema);
+  silc_free(p);
 }
 
 /* Increase semaphore */
@@ -556,6 +625,7 @@ SILC_TASK_CALLBACK(silc_fsm_sema_timedout)
 void silc_fsm_sema_post(SilcFSMSema sema)
 {
   SilcFSM fsm;
+  SilcFSMSemaPost p;
   SilcMutex lock = sema->fsm->u.m.lock;
 
   SILC_LOG_DEBUG(("Posting semaphore %p", sema));
@@ -570,7 +640,42 @@ void silc_fsm_sema_post(SilcFSMSema sema)
                                    fsm);
       fsm->sema = NULL;
     }
-    silc_fsm_signal(fsm);
+
+    p = silc_calloc(1, sizeof(*p));
+    if (!p)
+      continue;
+    p->sema = sema;
+    p->fsm = fsm;
+    silc_fsm_sema_ref(sema);
+
+    /* Signal through scheduler.  Wake up destination scheduler in case
+       caller is a real thread. */
+    silc_schedule_task_add_timeout(fsm->schedule, silc_fsm_signal, p, 0, 1);
+    silc_schedule_wakeup(fsm->schedule);
+  }
+
+  silc_mutex_unlock(lock);
+}
+
+/* Post thread termination semaphore.  Special function used only to
+   signal thread termination when SILC_FSM_THREAD_WAIT was used. */
+
+static void silc_fsm_thread_termination_post(SilcFSMSema sema)
+{
+  SilcFSM fsm;
+  SilcMutex lock = sema->fsm->u.m.lock;
+
+  SILC_LOG_DEBUG(("Post thread termination semaphore %p", sema));
+
+  silc_mutex_lock(lock);
+
+  silc_list_start(sema->waiters);
+  while ((fsm = silc_list_get(sema->waiters)) != SILC_LIST_END) {
+    /* Signal on thread termination.  Wake up destination scheduler in case
+       caller is a real thread. */
+    silc_list_del(sema->waiters, fsm);
+    silc_fsm_continue(fsm);
+    silc_schedule_wakeup(fsm->schedule);
   }
 
   silc_mutex_unlock(lock);
index eca7440929ca0a57fa195a1317c3c9457adf1136..72f11189a509837a07d7d767f797dbc4c8a63461 100644 (file)
@@ -183,17 +183,23 @@ typedef void (*SilcFSMThreadDestructor)(SilcFSMThread thread,
  *
  * DESCRIPTION
  *
- *    This macro is used to declare a FSM state function.
+ *    This macro is used to declare a FSM state function.  The `fsm' is
+ *    the SilcFSM or SilcFSMThread context, the `fsm_context' is the context
+ *    given as argument to silc_fsm_alloc, silc_fsm_init, silc_fsm_thread_init,
+ *    or silc_fsm_thread_alloc function.  The `state_context' is the optional
+ *    state specific context set with silc_fsm_set_state_context function.
  *
  * SOURCE
  */
 #define SILC_FSM_STATE(name)                                           \
-SilcFSMStatus name(struct SilcFSMObject *fsm, void *fsm_context)
+SilcFSMStatus name(struct SilcFSMObject *fsm, void *fsm_context,       \
+                  void *state_context)
 /***/
 
 /* State function callback */
 typedef SilcFSMStatus (*SilcFSMStateCallback)(struct SilcFSMObject *fsm,
-                                             void *fsm_context);
+                                             void *fsm_context,
+                                             void *state_context);
 
 /****d* silcutil/SilcFSMAPI/SILC_FSM_CALL
  *
@@ -261,7 +267,7 @@ do {                                                \
     silc_fsm_continue(fsm);                    \
 } while(0)
 
-/****d* silcutil/SilcFSMAPI/SILC_FSM_CALL_CONTINUE
+/****d* silcutil/SilcFSMAPI/SILC_FSM_CALL_CONTINUE_SYNC
  *
  * NAME
  *
@@ -309,7 +315,7 @@ do {                                                \
  *    This macro is the only way to safely make sure that the thread has
  *    terminated by the time FSM continues from the waiting state.  Using
  *    semaphores to signal from the thread before SILC_FSM_FINISH is returned
- *    works with normal FSM threads, but especially with real system threads,
+ *    works with normal FSM threads, but especially with real system threads
  *    it does not guarantee that the FSM won't continue before the thread has
  *    actually terminated.  Usually this is not a problem, but it can be a
  *    problem if the FSM is waiting to be freed or uninitialized.  In this
@@ -371,10 +377,10 @@ SilcFSM silc_fsm_alloc(void *fsm_context,
  * SYNOPSIS
  *
  *    SilcBool silc_fsm_init(SilcFSM fsm,
- *                       void *fsm_context,
- *                       SilcFSMDestructor destructor,
- *                       void *destructor_context,
- *                       SilcSchedule schedule);
+ *                           void *fsm_context,
+ *                           SilcFSMDestructor destructor,
+ *                           void *destructor_context,
+ *                           SilcSchedule schedule);
  *
  * DESCRIPTION
  *
@@ -394,10 +400,10 @@ SilcFSM silc_fsm_alloc(void *fsm_context,
  *
  ***/
 SilcBool silc_fsm_init(SilcFSM fsm,
-                  void *fsm_context,
-                   SilcFSMDestructor destructor,
-                   void *destructor_context,
-                   SilcSchedule schedule);
+                      void *fsm_context,
+                       SilcFSMDestructor destructor,
+                       void *destructor_context,
+                       SilcSchedule schedule);
 
 /****f* silcutil/SilcFSMAPI/silc_fsm_thread_alloc
  *
@@ -474,7 +480,7 @@ SilcFSMThread silc_fsm_thread_alloc(SilcFSM fsm,
  *
  * SYNOPSIS
  *
- *    SilcBool silc_fsm_thread_init(SilcFSMThread thread,
+ *    void silc_fsm_thread_init(SilcFSMThread thread,
  *                              SilcFSM fsm,
  *                              void *thread_context,
  *                              SilcFSMThreadDestructor destructor,
@@ -503,7 +509,7 @@ SilcFSMThread silc_fsm_thread_alloc(SilcFSM fsm,
  *    silc_fsm_start(&thread, first_state);
  *
  ***/
-SilcBool silc_fsm_thread_init(SilcFSMThread thread,
+void silc_fsm_thread_init(SilcFSMThread thread,
                          SilcFSM fsm,
                          void *thread_context,
                          SilcFSMThreadDestructor destructor,
@@ -633,6 +639,11 @@ void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
  *    the specified timeout.  This function is used with both SilcFSM and
  *    SilcFSMThread contexts.
  *
+ * NOTES
+ *
+ *    If both `seconds' and `useconds' are 0, the effect is same as calling
+ *    silc_fsm_next function, and SILC_FSM_CONTINUE must be returned.
+ *
  * EXAMPLE
  *
  *    // Move to next state after 10 seconds
@@ -643,6 +654,58 @@ void silc_fsm_next(void *fsm, SilcFSMStateCallback next_state);
 void silc_fsm_next_later(void *fsm, SilcFSMStateCallback next_state,
                         SilcUInt32 seconds, SilcUInt32 useconds);
 
+/****f* silcutil/SilcFSMAPI/silc_fsm_continue
+ *
+ * SYNOPSIS
+ *
+ *    void silc_fsm_continue(void *fsm);
+ *
+ * DESCRIPTION
+ *
+ *    Continues in the state machine from a SILC_FSM_WAIT state.  This can
+ *    be called from outside waiting FSM to continue to the next state.
+ *    This function can be used instead of SILC_FSM_CALL_CONTINUE macro
+ *    in case the SILC_FSM_CALL was not used.  This must not be used if
+ *    SILC_FSM_CALL was used.  This function is used with both SilcFSM and
+ *    SilcFSMThread contexts.
+ *
+ ***/
+void silc_fsm_continue(void *fsm);
+
+/****f* silcutil/SilcFSMAPI/silc_fsm_continue_sync
+ *
+ * SYNOPSIS
+ *
+ *    void silc_fsm_continue_sync(void *fsm);
+ *
+ * DESCRIPTION
+ *
+ *    Continues immediately in the state machine from a SILC_FSM_WAIT state.
+ *    This can be called from outside waiting FSM to immediately continue to
+ *    the next state.  This function can be used instead of the
+ *    SILC_FSM_CALL_CONTINUE_SYNC macro in case the SILC_FSM_CALL was not used.
+ *    This must not be used if SILC_FSM_CALL was used.  This function is used
+ *    with both SilcFSM and SilcFSMThread contexts.
+ *
+ ***/
+void silc_fsm_continue_sync(void *fsm);
+
+/****f* silcutil/SilcFSMAPI/silc_fsm_set_context
+ *
+ * SYNOPSIS
+ *
+ *    void silc_fsm_set_context(void *fsm, void *fsm_context);
+ *
+ * DESCRIPTION
+ *
+ *    Set new context for the `fsm'.  This function can be used to change
+ *    the context inside the `fsm', if needed.  This function is used with
+ *    both SilcFSM and SilcFSMThread contexts.  The context is the
+ *    `fsm_context' in the state function (SILC_FSM_STATE).
+ *
+ ***/
+void silc_fsm_set_context(void *fsm, void *fsm_context);
+
 /****f* silcutil/SilcFSMAPI/silc_fsm_get_context
  *
  * SYNOPSIS
@@ -659,20 +722,36 @@ void silc_fsm_next_later(void *fsm, SilcFSMStateCallback next_state,
  ***/
 void *silc_fsm_get_context(void *fsm);
 
-/****f* silcutil/SilcFSMAPI/silc_fsm_set_context
+/****f* silcutil/SilcFSMAPI/silc_fsm_set_state_context
  *
  * SYNOPSIS
  *
- *    void silc_fsm_set_context(void *fsm, void *fsm_context);
+ *    void silc_fsm_set_state_context(void *fsm, void *state_context);
  *
  * DESCRIPTION
  *
- *    Set new context for the `fsm'.  This function can be used to change
- *    the context inside the `fsm', if needed.  This function is used with
- *    both SilcFSM and SilcFSMThread contexts.
+ *    Set's a state specific context for the `fsm'.  This function can be
+ *    used to change the state context inside the `fsm', if needed.  This
+ *    function is used with both SilcFSM and SilcFSMThread contexts.  The
+ *    context is the `state_context' in the state function (SILC_FSM_STATE).
  *
  ***/
-void silc_fsm_set_context(void *fsm, void *fsm_context);
+void silc_fsm_set_state_context(void *fsm, void *state_context);
+
+/****f* silcutil/SilcFSMAPI/silc_fsm_get_state_context
+ *
+ * SYNOPSIS
+ *
+ *    void *silc_fsm_get_state_context(void *fsm);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the state context associated with the `fsm'.  It is the context
+ *    that was set with silc_fsm_set_state_context function.  This function
+ *    is used with both SilcFSM and SilcFSMThread contexts.
+ *
+ ***/
+void *silc_fsm_get_state_context(void *fsm);
 
 /****f* silcutil/SilcFSMAPI/silc_fsm_get_schedule
  *
@@ -693,12 +772,25 @@ void silc_fsm_set_context(void *fsm, void *fsm_context);
  *    scheduler in the thread.  Note that, once the thread finishes the
  *    returned SilcSchedule becomes invalid.
  *
- *    Every other time this returns the SilcSchedule pointer that was given
+ *    In other times this returns the SilcSchedule pointer that was given
  *    to silc_fsm_alloc or silc_fsm_init.
  *
  ***/
 SilcSchedule silc_fsm_get_schedule(void *fsm);
 
+/****f* silcutil/SilcFSMAPI/silc_fsm_get_machine
+ *
+ * SYNOPSIS
+ *
+ *    SilcFSM silc_fsm_get_machine(SilcFSMThread thread);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the machine from the FSM thread indicated by `thread'.
+ *
+ ***/
+SilcFSM silc_fsm_get_machine(SilcFSMThread thread);
+
 
 /* FSM Semaphores */
 
@@ -755,10 +847,6 @@ typedef struct SilcFSMSemaObject SilcFSMSemaStruct;
  *    for semaphore.  Use the SILC_FSM_SEMA_POST macro to increment the
  *    counter and wake up all waiters.
  *
- *    FSM semaphores are machine specific.  The context cannot be shared
- *    between multiple machines.  The same context naturally can be shared
- *    between the machine and its threads.
- *
  ***/
 SilcFSMSema silc_fsm_sema_alloc(SilcFSM fsm, SilcUInt32 value);
 
@@ -847,14 +935,16 @@ do {                                              \
  *
  * NAME
  *
- *    SILC_FSM_SEMA_TIMEDWAIT(semaphore, seconds, useconds)
+ *    SILC_FSM_SEMA_TIMEDWAIT(semaphore, seconds, useconds, timedout)
  *
  * DESCRIPTION
  *
  *    Macro used to wait for the `semaphore' to become non-zero, or until
  *    the timeout specified by `seconds' and `useconds' has elapsed.  If
  *    the timeout occurs before the semaphore becomes non-zero, the machine
- *    will wakeup.  This macro can only be used in FSM state functions.
+ *    will wakeup.  The `timedout' is SilcBool pointer and if it is
+ *    non-NULL indication of whether timeout occurred or not is saved to
+ *    the pointer.  This macro can only be used in FSM state functions.
  *    When the semaphore is signalled or timedout the FSM will re-enter
  *    the current state (or state that was set with silc_fsm_next before
  *    waiting).
@@ -863,22 +953,28 @@ do {                                              \
  *
  *    SILC_FSM_STATE(silc_foo_state)
  *    {
+ *      SilcBool timedout;
  *      ...
  *
+ *
  *      // Wait here for async call to complete, or 10 seconds for timeout
- *      SILC_FSM_SEMA_TIMEDWAIT(ctx->async_sema, 10, 0);
+ *      SILC_FSM_SEMA_TIMEDWAIT(ctx->async_sema, 10, 0, &timedout);
+ *
+ *      // See if timeout occurred
+ *      if (timedout == TRUE)
+ *        fatal(error);
  *
- *      // Async call completed or timeout occurred
+ *      // Async call completed
  *      if (ctx->async_success == FALSE)
  *        fatal(error);
  *      ...
  *    }
  *
  ***/
-#define SILC_FSM_SEMA_TIMEDWAIT(sema, seconds, useconds)               \
-do {                                                                   \
-  if (silc_fsm_sema_timedwait(sema, fsm, seconds, useconds) == 0)      \
-    return SILC_FSM_WAIT;                                              \
+#define SILC_FSM_SEMA_TIMEDWAIT(sema, seconds, useconds, ret_to)         \
+do {                                                                     \
+  if (silc_fsm_sema_timedwait(sema, fsm, seconds, useconds, ret_to) == 0) \
+    return SILC_FSM_WAIT;                                                \
 } while(0)
 
 /****f* silcutil/SilcFSMAPI/SILC_FSM_SEMA_POST
index 455d8b9975d5b2ffe9558d593bfadc863669fbbd..9246878f0904c860ce46f1eaad688875fd52a18c 100644 (file)
@@ -30,7 +30,9 @@
 struct SilcFSMSemaObject {
   SilcFSM fsm;                         /* Machine */
   SilcList waiters;                    /* List of SilcFSM pointers */
-  SilcUInt32 value;                    /* Current semaphore value */
+  unsigned int value     : 21;         /* Current semaphore value */
+  unsigned int refcnt    : 10;         /* Reference counter */
+  unsigned int allocated : 1;          /* Set if allocated */
 };
 
 /* FSM and FSM thread context */
@@ -40,6 +42,7 @@ struct SilcFSMObject {
   SilcSchedule schedule;               /* Scheduler */
   SilcFSMSema sema;                    /* Valid if waiting sema timeout */
   SilcFSMStateCallback next_state;     /* Next state in machine */
+  void *state_context;                 /* Extra state specific context */
   SilcFSMDestructor destructor;                /* Destructor */
   void *destructor_context;
   union {
@@ -63,6 +66,12 @@ struct SilcFSMObject {
   unsigned int synchronous      : 1;    /* Set if silc_fsm_start_sync called */
 };
 
+/* Semaphore post context */
+typedef struct {
+  SilcFSMSema sema;                    /* Semaphore */
+  SilcFSM fsm;                         /* Signalled FSM */
+} *SilcFSMSemaPost;
+
 /* Used internally by the SILC_FSM_CALL macros to detect whether async
    call is really async or not. */
 static inline
@@ -73,17 +82,14 @@ SilcBool silc_fsm_set_call(struct SilcFSMObject *fsm, SilcBool async_call)
   return old;
 }
 
-/* Continues after callback */
-void silc_fsm_continue(void *fsm);
-void silc_fsm_continue_sync(void *fsm);
-
 /* Wait for thread to terminate */
 SilcBool silc_fsm_thread_wait(void *fsm, void *thread);
 
 /* Semaphores */
 SilcUInt32 silc_fsm_sema_wait(SilcFSMSema sema, void *fsm);
 SilcUInt32 silc_fsm_sema_timedwait(SilcFSMSema sema, void *fsm,
-                                  SilcUInt32 seconds, SilcUInt32 useconds);
+                                  SilcUInt32 seconds, SilcUInt32 useconds,
+                                  SilcBool *ret_to);
 void silc_fsm_sema_post(SilcFSMSema sema);
 
 #endif /* SILCFSM_I_H */
index 03b1ac796505d34693c930349d779c76b0d3477a..9fbd98954bad391dd1f1009885ddc63daaf52fed 100644 (file)
@@ -25,7 +25,7 @@
    hash table. */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silchashtable.h"
 
 /* Define to 1 if you want hash table debug enabled */
@@ -430,18 +430,20 @@ SilcUInt32 silc_hash_table_count(SilcHashTable ht)
    hash table. This function quarantees that the entry is always added
    to the hash table reliably (it is collision resistant). */
 
-void silc_hash_table_add(SilcHashTable ht, void *key, void *context)
+SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context)
 {
-  silc_hash_table_add_internal(ht, key, context, ht->hash,
-                              ht->hash_user_context);
+  return silc_hash_table_add_internal(ht, key, context, ht->hash,
+                                     ht->hash_user_context);
 }
 
 /* Same as above but with specific hash function and user context. */
 
-void silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
-                            SilcHashFunction hash, void *hash_user_context)
+SilcBool silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
+                                SilcHashFunction hash,
+                                void *hash_user_context)
 {
-  silc_hash_table_add_internal(ht, key, context, hash, hash_user_context);
+  return silc_hash_table_add_internal(ht, key, context,
+                                     hash, hash_user_context);
 }
 
 /* Same as above but if the `key' already exists in the hash table
@@ -449,19 +451,21 @@ void silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
    the `context. The destructor function will be called for the
    replaced key and context. */
 
-void silc_hash_table_replace(SilcHashTable ht, void *key, void *context)
+SilcBool silc_hash_table_replace(SilcHashTable ht, void *key, void *context)
 {
-  silc_hash_table_replace_internal(ht, key, context, ht->hash,
-                                  ht->hash_user_context);
+  return silc_hash_table_replace_internal(ht, key, context, ht->hash,
+                                         ht->hash_user_context);
 }
 
 /* Same as above but with specific hash function. */
 
-void silc_hash_table_replace_ext(SilcHashTable ht, void *key, void *context,
-                                SilcHashFunction hash,
-                                void *hash_user_context)
+SilcBool silc_hash_table_replace_ext(SilcHashTable ht, void *key,
+                                    void *context,
+                                    SilcHashFunction hash,
+                                    void *hash_user_context)
 {
-  silc_hash_table_replace_internal(ht, key, context, hash, hash_user_context);
+  return silc_hash_table_replace_internal(ht, key, context,
+                                         hash, hash_user_context);
 }
 
 /* Removes the entry from the hash table by the provided `key'. This will
index 012ce5ee36c121f3aecd0e7baadaf2fc0a3b5929..687170f9a4585a7efb9a9b99a9d8754dc5900da7 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2003 Pekka Riikonen
+  Copyright (C) 2001 - 2005 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -39,6 +39,9 @@
  * SilcHashTableList structure and traverse the hash table inside while()
  * using the list structure. Both are equally fast.
  *
+ * The hash table is not thread safe.  If same hash table context is used in
+ * multi thread environment concurrency control must be employed.
+ *
  ***/
 
 #ifndef SILCHASHTABLE_H
@@ -115,7 +118,7 @@ typedef SilcUInt32 (*SilcHashFunction)(void *key, void *user_context);
  * SYNOPSIS
  *
  *    typedef SilcBool (*SilcHashCompare)(void *key1, void *key2,
- *                                    void *user_context);
+ *                                        void *user_context);
  *
  * DESCRIPTION
  *
@@ -126,7 +129,8 @@ typedef SilcUInt32 (*SilcHashFunction)(void *key, void *user_context);
  *    to the callback.
  *
  ***/
-typedef SilcBool (*SilcHashCompare)(void *key1, void *key2, void *user_context);
+typedef SilcBool (*SilcHashCompare)(void *key1, void *key2,
+                                   void *user_context);
 
 /****f* silcutil/SilcHashTableAPI/SilcHashDestructor
  *
@@ -244,7 +248,7 @@ SilcUInt32 silc_hash_table_count(SilcHashTable ht);
  *
  * SYNOPSIS
  *
- *    void silc_hash_table_add(SilcHashTable ht, void *key, void *context);
+ *    SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context);
  *
  * DESCRIPTION
  *
@@ -254,13 +258,14 @@ SilcUInt32 silc_hash_table_count(SilcHashTable ht);
  *    to the hash table reliably (it is collision resistant).
  *
  ***/
-void silc_hash_table_add(SilcHashTable ht, void *key, void *context);
+SilcBool silc_hash_table_add(SilcHashTable ht, void *key, void *context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_replace
  *
  * SYNOPSIS
  *
- *    void silc_hash_table_replace(SilcHashTable ht, void *key, void *context);
+ *    SilcBool silc_hash_table_replace(SilcHashTable ht, void *key,
+ *                                     void *context);
  *
  * DESCRIPTION
  *
@@ -270,7 +275,7 @@ void silc_hash_table_add(SilcHashTable ht, void *key, void *context);
  *    replaced key and context.
  *
  ***/
-void silc_hash_table_replace(SilcHashTable ht, void *key, void *context);
+SilcBool silc_hash_table_replace(SilcHashTable ht, void *key, void *context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_del
  *
@@ -292,7 +297,7 @@ SilcBool silc_hash_table_del(SilcHashTable ht, void *key);
  * SYNOPSIS
  *
  *    SilcBool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
- *                                        void *context);
+ *                                            void *context);
  *
  * DESCRIPTION
  *
@@ -303,14 +308,14 @@ SilcBool silc_hash_table_del(SilcHashTable ht, void *key);
  *
  ***/
 SilcBool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
-                                   void *context);
+                                       void *context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_find
  *
  * SYNOPSIS
  *
  *    SilcBool silc_hash_table_find(SilcHashTable ht, void *key,
- *                              void **ret_key, void **ret_context);
+ *                                  void **ret_key, void **ret_context);
  *
  * DESCRIPTION
  *
@@ -322,14 +327,14 @@ SilcBool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
  *
  ***/
 SilcBool silc_hash_table_find(SilcHashTable ht, void *key,
-                         void **ret_key, void **ret_context);
+                             void **ret_key, void **ret_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_find_by_context
  *
  * SYNOPSIS
  *
  *    SilcBool silc_hash_table_find_by_context(SilcHashTable ht, void *key,
- *                                         void *context, void **ret_key);
+ *                                             void *context, void **ret_key);
  *
  * DESCRIPTION
  *
@@ -343,7 +348,7 @@ SilcBool silc_hash_table_find(SilcHashTable ht, void *key,
  *
  ***/
 SilcBool silc_hash_table_find_by_context(SilcHashTable ht, void *key,
-                                    void *context, void **ret_key);
+                                        void *context, void **ret_key);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_find_foreach
  *
@@ -451,7 +456,7 @@ void silc_hash_table_list_reset(SilcHashTableList *htl);
  * SYNOPSIS
  *
  *    SilcBool silc_hash_table_get(SilcHashTableList *htl, void **key,
- *                             void **context);
+ *                                 void **context);
  *
  * DESCRIPTION
  *
@@ -460,7 +465,8 @@ void silc_hash_table_list_reset(SilcHashTableList *htl);
  *    any entrys.
  *
  ***/
-SilcBool silc_hash_table_get(SilcHashTableList *htl, void **key, void **context);
+SilcBool silc_hash_table_get(SilcHashTableList *htl,
+                            void **key, void **context);
 
 
 /* Extended hash table interface (same as above but with specific
@@ -470,9 +476,10 @@ SilcBool silc_hash_table_get(SilcHashTableList *htl, void **key, void **context)
  *
  * SYNOPSIS
  *
- *    void silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
- *                                 SilcHashFunction hash,
- *                                 void *hash_user_context);
+ *    SilcBool silc_hash_table_add_ext(SilcHashTable ht, void *key,
+ *                                     void *context,
+ *                                     SilcHashFunction hash,
+ *                                     void *hash_user_context);
  *
  * DESCRIPTION
  *
@@ -485,17 +492,19 @@ SilcBool silc_hash_table_get(SilcHashTableList *htl, void **key, void **context)
  *    function. If not provided the hash table's default is used.
  *
  ***/
-void silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
-                            SilcHashFunction hash, void *hash_user_context);
+SilcBool silc_hash_table_add_ext(SilcHashTable ht,
+                                void *key, void *context,
+                                SilcHashFunction hash,
+                                void *hash_user_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_replace_ext
  *
  * SYNOPSIS
  *
- *    void silc_hash_table_replace_ext(SilcHashTable ht, void *key,
- *                                     void *context,
- *                                     SilcHashFunction hash,
- *                                     void *hash_user_context);
+ *    SilcBool silc_hash_table_replace_ext(SilcHashTable ht, void *key,
+ *                                         void *context,
+ *                                         SilcHashFunction hash,
+ *                                         void *hash_user_context);
  *
  * DESCRIPTION
  *
@@ -508,21 +517,22 @@ void silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
  *    function. If not provided the hash table's default is used.
  *
  ***/
-void silc_hash_table_replace_ext(SilcHashTable ht, void *key, void *context,
-                                SilcHashFunction hash,
-                                void *hash_user_context);
+SilcBool silc_hash_table_replace_ext(SilcHashTable ht,
+                                    void *key, void *context,
+                                    SilcHashFunction hash,
+                                    void *hash_user_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_del_ext
  *
  * SYNOPSIS
  *
  *    SilcBool silc_hash_table_del_ext(SilcHashTable ht, void *key,
- *                                 SilcHashFunction hash,
- *                                 void *hash_user_context,
- *                                 SilcHashCompare compare,
- *                                 void *compare_user_context,
- *                                 SilcHashDestructor destructor,
- *                                 void *destructor_user_context);
+ *                                     SilcHashFunction hash,
+ *                                     void *hash_user_context,
+ *                                     SilcHashCompare compare,
+ *                                     void *compare_user_context,
+ *                                     SilcHashDestructor destructor,
+ *                                     void *destructor_user_context);
  *
  * DESCRIPTION
  *
@@ -539,25 +549,26 @@ void silc_hash_table_replace_ext(SilcHashTable ht, void *key, void *context,
  *
  ***/
 SilcBool silc_hash_table_del_ext(SilcHashTable ht, void *key,
-                            SilcHashFunction hash,
-                            void *hash_user_context,
-                            SilcHashCompare compare,
-                            void *compare_user_context,
-                            SilcHashDestructor destructor,
-                            void *destructor_user_context);
+                                SilcHashFunction hash,
+                                void *hash_user_context,
+                                SilcHashCompare compare,
+                                void *compare_user_context,
+                                SilcHashDestructor destructor,
+                                void *destructor_user_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_del_by_context_ext
  *
  * SYNOPSIS
  *
- *    SilcBool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
- *                                            void *context,
- *                                            SilcHashFunction hash,
- *                                            void *hash_user_context,
- *                                            SilcHashCompare compare,
- *                                            void *compare_user_context,
- *                                            SilcHashDestructor destructor,
- *                                            void *destructor_user_context);
+ *    SilcBool
+ *    silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
+ *                                       void *context,
+ *                                       SilcHashFunction hash,
+ *                                       void *hash_user_context,
+ *                                       SilcHashCompare compare,
+ *                                       void *compare_user_context,
+ *                                       SilcHashDestructor destructor,
+ *                                       void *destructor_user_context);
  *
  * DESCRIPTION
  *
@@ -575,24 +586,24 @@ SilcBool silc_hash_table_del_ext(SilcHashTable ht, void *key,
  *
  ***/
 SilcBool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
-                                       void *context,
-                                       SilcHashFunction hash,
-                                       void *hash_user_context,
-                                       SilcHashCompare compare,
-                                       void *compare_user_context,
-                                       SilcHashDestructor destructor,
-                                       void *destructor_user_context);
+                                           void *context,
+                                           SilcHashFunction hash,
+                                           void *hash_user_context,
+                                           SilcHashCompare compare,
+                                           void *compare_user_context,
+                                           SilcHashDestructor destructor,
+                                           void *destructor_user_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_find_ext
  *
  * SYNOPSIS
  *
  *    SilcBool silc_hash_table_find_ext(SilcHashTable ht, void *key,
- *                                  void **ret_key, void **ret_context,
- *                                  SilcHashFunction hash,
- *                                  void *hash_user_context,
- *                                  SilcHashCompare compare,
- *                                  void *compare_user_context);
+ *                                      void **ret_key, void **ret_context,
+ *                                      SilcHashFunction hash,
+ *                                      void *hash_user_context,
+ *                                      SilcHashCompare compare,
+ *                                      void *compare_user_context);
  *
  * DESCRIPTION
  *
@@ -609,22 +620,23 @@ SilcBool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
  *
  ***/
 SilcBool silc_hash_table_find_ext(SilcHashTable ht, void *key,
-                             void **ret_key, void **ret_context,
-                             SilcHashFunction hash,
-                             void *hash_user_context,
-                             SilcHashCompare compare,
-                             void *compare_user_context);
+                                 void **ret_key, void **ret_context,
+                                 SilcHashFunction hash,
+                                 void *hash_user_context,
+                                 SilcHashCompare compare,
+                                 void *compare_user_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_find_by_context_ext
  *
  * SYNOPSIS
  *
- *    SilcBool silc_hash_table_find_by_context_ext(SilcHashTable ht, void *key,
- *                                             void *context, void **ret_key,
- *                                             SilcHashFunction hash,
- *                                             void *hash_user_context,
- *                                             SilcHashCompare compare,
- *                                             void *compare_user_context);
+ *    SilcBool
+ *    silc_hash_table_find_by_context_ext(SilcHashTable ht, void *key,
+ *                                        void *context, void **ret_key,
+ *                                        SilcHashFunction hash,
+ *                                        void *hash_user_context,
+ *                                        SilcHashCompare compare,
+ *                                        void *compare_user_context);
  *
  * DESCRIPTION
  *
@@ -643,11 +655,11 @@ SilcBool silc_hash_table_find_ext(SilcHashTable ht, void *key,
  *
  ***/
 SilcBool silc_hash_table_find_by_context_ext(SilcHashTable ht, void *key,
-                                        void *context, void **ret_key,
-                                        SilcHashFunction hash,
-                                        void *hash_user_context,
-                                        SilcHashCompare compare,
-                                        void *compare_user_context);
+                                            void *context, void **ret_key,
+                                            SilcHashFunction hash,
+                                            void *hash_user_context,
+                                            SilcHashCompare compare,
+                                            void *compare_user_context);
 
 /****f* silcutil/SilcHashTableAPI/silc_hash_table_find_foreach_ext
  *
index 50213491f0b361239d015a5cd08606752499b777..1cd197700eea7cf9076fcab1855d0bbdfda55c25 100644 (file)
@@ -45,8 +45,8 @@ typedef struct {
   void *head;                       /* Start of the list */
   void *tail;                       /* End of the list */
   void *current;                    /* Current pointer in list */
-  unsigned int next_offset : 16;     /* Offset to 'next' pointer */
-  unsigned int prev_offset : 16;     /* Offset to 'prev' pointer */
+  SilcUInt16 next_offset;           /* Offset to 'next' pointer */
+  SilcUInt16 prev_offset;           /* Offset to 'prev' pointer */
   unsigned int prev_set    : 1;             /* Set if 'prev' exists */
   unsigned int end_set     : 1;             /* Set if silc_list_end was called */
   unsigned int count       : 30;     /* Number of entries in the list */
index 0f017449d195e9eb2af2950ddc039b12dcda157b..53f70919e5b3ad0bbf6cc5786ad3db56226c196f 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* SilcLogSettings context */
 typedef struct {
index d2a0dba459f9c6bf563dd53e0b95da7e2cc2b734..3ab49aa290903605df16f3f7bf139119a145f2e7 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifndef SILC_STACKTRACE
 
index d7d2ddc24b727d632abea52f0d150e665446f4b0..5aa66c17362d001a6241eaecb173c53d983dec66 100644 (file)
 
 */
 
-#include "silcincludes.h"
-#include "silcmime.h"
+#include "silc.h"
 
-struct SilcMimeStruct {
-  SilcHashTable fields;
-  unsigned char *data;
-  SilcUInt32 data_len;
-  SilcDList multiparts;
-  char *boundary;
-  char *multitype;
-};
+/************************ Static utility functions **************************/
 
-struct SilcMimeAssemblerStruct {
-  SilcHashTable fragments;
-};
+/* MIME fields destructor */
 
 static void silc_mime_field_dest(void *key, void *context, void *user_context)
 {
@@ -39,6 +29,28 @@ static void silc_mime_field_dest(void *key, void *context, void *user_context)
   silc_free(context);
 }
 
+/* Assembler fragment destructor */
+
+static void silc_mime_assembler_dest(void *key, void *context,
+                                    void *user_context)
+{
+  silc_free(key);
+  silc_hash_table_free(context);
+}
+
+/* Assembler partial MIME destructor */
+
+static void silc_mime_assemble_dest(void *key, void *context,
+                                   void *user_context)
+{
+  silc_mime_free(context);
+}
+
+
+/******************************* Public API *********************************/
+
+/* Allocate MIME context */
+
 SilcMime silc_mime_alloc(void)
 {
   SilcMime mime;
@@ -58,6 +70,8 @@ SilcMime silc_mime_alloc(void)
   return mime;
 }
 
+/* Free MIME context */
+
 void silc_mime_free(SilcMime mime)
 {
   SilcMime m;
@@ -77,12 +91,7 @@ void silc_mime_free(SilcMime mime)
   silc_free(mime);
 }
 
-static void silc_mime_assembler_dest(void *key, void *context,
-                                                         void *user_context)
-{
-  silc_free(key);
-  silc_hash_table_free(context);
-}
+/* Allocate MIME assembler */
 
 SilcMimeAssembler silc_mime_assembler_alloc(void)
 {
@@ -104,15 +113,20 @@ SilcMimeAssembler silc_mime_assembler_alloc(void)
   return assembler;
 }
 
+/* Free MIME assembler */
+
 void silc_mime_assembler_free(SilcMimeAssembler assembler)
 {
   silc_hash_table_free(assembler->fragments);
   silc_free(assembler);
 }
 
-SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len)
+/* Decode MIME message */
+
+SilcMime silc_mime_decode(SilcMime mime, const unsigned char *data,
+                         SilcUInt32 data_len)
 {
-  SilcMime mime;
+  SilcMime m = NULL;
   int i, k;
   char *tmp, *field, *value, *line;
 
@@ -121,9 +135,12 @@ SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len)
   if (!data)
     return NULL;
 
-  mime = silc_mime_alloc();
-  if (!mime)
-    return NULL;
+  if (!mime) {
+    mime = silc_mime_alloc();
+    if (!mime)
+      return NULL;
+    m = mime;
+  }
 
   /* Parse the fields */
   line = tmp = (char *)data;
@@ -255,7 +272,7 @@ SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len)
          k -= 2;
 
          /* Parse the part */
-         p = silc_mime_decode(line, k - i);
+         p = silc_mime_decode(NULL, line, k - i);
          if (!p)
            goto err;
 
@@ -275,10 +292,13 @@ SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len)
   return mime;
 
  err:
-  silc_mime_free(mime);
+  if (m)
+    silc_mime_free(m);
   return NULL;
 }
 
+/* Encode MIME message */
+
 unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len)
 {
   SilcMime part;
@@ -379,11 +399,7 @@ unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len)
   return ret;
 }
 
-static void silc_mime_assemble_dest(void *key, void *context,
-                                                        void *user_context)
-{
-  silc_mime_free(context);
-}
+/* Assembles MIME message from partial MIME messages */
 
 SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial)
 {
@@ -512,7 +528,7 @@ SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial)
   }
 
   /* Now parse the complete MIME message and deliver it */
-  complete = silc_mime_decode((const unsigned char *)compbuf->head,
+  complete = silc_mime_decode(NULL, (const unsigned char *)compbuf->head,
                              silc_buffer_truelen(compbuf));
   if (!complete)
     goto err;
@@ -532,6 +548,8 @@ SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial)
   return NULL;
 }
 
+/* Encodes partial MIME messages */
+
 SilcDList silc_mime_encode_partial(SilcMime mime, int max_size)
 {
   unsigned char *buf, *tmp;
@@ -642,6 +660,8 @@ SilcDList silc_mime_encode_partial(SilcMime mime, int max_size)
   return list;
 }
 
+/* Free partial MIME list */
+
 void silc_mime_partial_free(SilcDList partials)
 {
   SilcBuffer buf;
@@ -655,6 +675,8 @@ void silc_mime_partial_free(SilcDList partials)
   silc_dlist_uninit(partials);
 }
 
+/* Add field */
+
 void silc_mime_add_field(SilcMime mime, const char *field, const char *value)
 {
   if (!mime || !field || !value)
@@ -663,6 +685,8 @@ void silc_mime_add_field(SilcMime mime, const char *field, const char *value)
   silc_hash_table_add(mime->fields, strdup(field), strdup(value));
 }
 
+/* Get field */
+
 const char *silc_mime_get_field(SilcMime mime, const char *field)
 {
   char *value;
@@ -677,6 +701,8 @@ const char *silc_mime_get_field(SilcMime mime, const char *field)
   return (const char *)value;
 }
 
+/* Add data */
+
 void silc_mime_add_data(SilcMime mime, const unsigned char *data,
                        SilcUInt32 data_len)
 {
@@ -690,6 +716,8 @@ void silc_mime_add_data(SilcMime mime, const unsigned char *data,
   mime->data_len = data_len;
 }
 
+/* Get data */
+
 const unsigned char *silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len)
 {
   if (!mime)
@@ -701,6 +729,8 @@ const unsigned char *silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len)
   return mime->data;
 }
 
+/* Returns TRUE if partial message */
+
 SilcBool silc_mime_is_partial(SilcMime mime)
 {
   const char *type = silc_mime_get_field(mime, "Content-Type");
@@ -713,6 +743,8 @@ SilcBool silc_mime_is_partial(SilcMime mime)
   return TRUE;
 }
 
+/* Set as multipart message */
+
 void silc_mime_set_multipart(SilcMime mime, const char *type,
                             const char *boundary)
 {
@@ -732,6 +764,8 @@ void silc_mime_set_multipart(SilcMime mime, const char *type,
   mime->multiparts = silc_dlist_init();
 }
 
+/* Add multipart */
+
 SilcBool silc_mime_add_multipart(SilcMime mime, SilcMime part)
 {
   if (!mime || !mime->multiparts || !part)
@@ -741,6 +775,8 @@ SilcBool silc_mime_add_multipart(SilcMime mime, SilcMime part)
   return TRUE;
 }
 
+/* Return TRUE if has multiparts */
+
 SilcBool silc_mime_is_multipart(SilcMime mime)
 {
   if (!mime)
@@ -749,6 +785,8 @@ SilcBool silc_mime_is_multipart(SilcMime mime)
   return mime->multiparts != NULL;
 }
 
+/* Returns multiparts */
+
 SilcDList silc_mime_get_multiparts(SilcMime mime, const char **type)
 {
   if (!mime)
index 62ebdefcef82efb8631863f21c06dd58b019c102..649c3d369c3e91a450c7de8a2d7f7242b6c6ce86 100644 (file)
@@ -116,28 +116,32 @@ void silc_mime_assembler_free(SilcMimeAssembler assembler);
  *
  * SYNOPSIS
  *
- *    SilcMime silc_mime_decode(const unsigned char *data,
+ *    SilcMime silc_mime_decode(SilcMime mime, const unsigned char *data,
  *                              SilcUInt32 data_len);
  *
  * DESCRIPTION
  *
  *    Decodes a MIME message and returns the parsed message into newly
- *    allocated SilcMime context.
+ *    allocated SilcMime context and returns it.  If `mime' is non-NULL
+ *    then the MIME message will be encoded into the pre-allocated `mime'
+ *    context and same context is returned.  If it is NULL then newly
+ *    allocated SilcMime context is returned.  On error NULL is returned.
  *
  * EXAMPLE
  *
  *    // Parse MIME message and get its content type
- *    mime = silc_mime_decode(data, data_len);
+ *    mime = silc_mime_decode(NULL, data, data_len);
  *    type = silc_mime_get_field(mime, "Content-Type");
  *    ...
  *
  *    // Assemble received MIME fragment
- *    mime = silc_mime_decode(data, data_len);
+ *    mime = silc_mime_decode(NULL, data, data_len);
  *    if (silc_mime_is_partial(mime) == TRUE)
  *      silc_mime_assmeble(assembler, mime);
  *
  ***/
-SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len);
+SilcMime silc_mime_decode(SilcMime mime, const unsigned char *data,
+                         SilcUInt32 data_len);
 
 /****f* silcutil/SILCMIMEAPI/silc_mime_encode
  *
@@ -377,4 +381,6 @@ SilcBool silc_mime_is_multipart(SilcMime mime);
  ***/
 SilcDList silc_mime_get_multiparts(SilcMime mime, const char **type);
 
+#include "silcmime_i.h"
+
 #endif /* SILCMIME_H */
diff --git a/lib/silcutil/silcmime_i.h b/lib/silcutil/silcmime_i.h
new file mode 100644 (file)
index 0000000..5721a5a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+
+  silcmime_i.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2005 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+
+*/
+
+#ifndef SILCMIME_I_H
+#define SILCMIME_I_H
+
+#ifndef SILCMIME_H
+#error "Do not include this header directly"
+#endif
+
+/* MIME context */
+struct SilcMimeStruct {
+  SilcHashTable fields;
+  unsigned char *data;
+  SilcUInt32 data_len;
+  SilcDList multiparts;
+  char *boundary;
+  char *multitype;
+};
+
+/* MIME assembler */
+struct SilcMimeAssemblerStruct {
+  SilcHashTable fragments;
+};
+
+#endif /* SILCMIME_I_H */
index c4686c6ef791a20e82b17d0b6f7372b1e415f4e3..2897b9c87f9eff51e115dcfce31a5697b51acae4 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Accepts a connection from a particular socket */
 
@@ -144,8 +144,9 @@ static void *silc_net_gethostbyaddr_thread(void *context)
 
 /* Resolves IP address for hostname. */
 
-SilcBool silc_net_gethostbyname(const char *name, SilcBool prefer_ipv6, char *address,
-                           SilcUInt32 address_len)
+SilcBool silc_net_gethostbyname(const char *name,
+                               SilcBool prefer_ipv6, char *address,
+                               SilcUInt32 address_len)
 {
 #ifdef HAVE_IPV6
   struct addrinfo hints, *ai, *tmp, *ip4 = NULL, *ip6 = NULL;
index c7ce66dcc190ef795fbfb96ebc93db1c18476345..8c5cfd66bc361af4b2feb589d5c1328c81daae5c 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Platform specific implementation */
 extern const SilcScheduleOps schedule_ops;
@@ -331,17 +331,17 @@ SilcBool silc_schedule_one(SilcSchedule schedule, int timeout_usecs)
   ret = schedule_ops.select(schedule, schedule->internal);
 
   switch (ret) {
+  case 0:
+    /* Timeout */
+    SILC_LOG_DEBUG(("Running timeout tasks"));
+    silc_schedule_dispatch_timeout(schedule, FALSE);
+    break;
   case -1:
     /* Error */
     if (errno == EINTR)
       break;
     SILC_LOG_ERROR(("Error in select(): %s", strerror(errno)));
     break;
-  case 0:
-    /* Timeout */
-    SILC_LOG_DEBUG(("Running timeout tasks"));
-    silc_schedule_dispatch_timeout(schedule, FALSE);
-    break;
   default:
     /* There is some data available now */
     SILC_LOG_DEBUG(("Running fd tasks"));
@@ -424,8 +424,6 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
     if (!ttask)
       goto out;
 
-    SILC_LOG_DEBUG(("Registering new timeout task %p", ttask));
-
     ttask->header.type = 1;
     ttask->header.callback = callback;
     ttask->header.context = context;
@@ -436,12 +434,15 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
       silc_gettimeofday(&ttask->timeout);
       ttask->timeout.tv_sec += seconds + (useconds / 1000000L);
       ttask->timeout.tv_usec += (useconds % 1000000L);
-      if (ttask->timeout.tv_usec > 999999L) {
+      if (ttask->timeout.tv_usec >= 1000000L) {
        ttask->timeout.tv_sec += 1;
        ttask->timeout.tv_usec -= 1000000L;
       }
     }
 
+    SILC_LOG_DEBUG(("New timeout task %p: sec=%d, usec=%d", ttask,
+                   seconds, useconds));
+
     /* Add task to correct spot so that the first task in the list has
        the earliest timeout. */
     silc_list_start(schedule->timeout_queue);
@@ -461,7 +462,7 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
   } else {
     /* Check if fd is already added */
     if (silc_hash_table_find(schedule->fd_queue, SILC_32_TO_PTR(fd),
-                            NULL, NULL))
+                            NULL, (void **)&task))
       goto out;
 
     /* Check max tasks */
@@ -475,7 +476,7 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
     if (!ftask)
       goto out;
 
-    SILC_LOG_DEBUG(("Registering new fd task %p fd=%d", ftask, fd));
+    SILC_LOG_DEBUG(("New fd task %p fd=%d", ftask, fd));
 
     ftask->header.type = 0;
     ftask->header.callback = callback;
index ec456dd8bf17a037edb3fe2913eab25807dd0c4a..0e1a6e83ffba0115ebc417e310785751ba3bdd60 100644 (file)
@@ -424,7 +424,7 @@ SilcTask silc_schedule_task_add(SilcSchedule schedule, SilcUInt32 fd,
  *
  ***/
 #define silc_schedule_task_add_timeout(schedule, callback, context, s, u) \
-  silc_schedule_task_add(schedule, 0, callback, context, s, u,            \
+  silc_schedule_task_add(schedule, 0, callback, context, s, u,           \
                         SILC_TASK_TIMEOUT)
 
 /****f* silcutil/SilcScheduleAPI/silc_schedule_task_del
index 815bbdb1796fc9c43e9d798b127e9cc75c2c66cb..e67678497ad964d66ece1505023e1870b78ef2a8 100644 (file)
@@ -17,7 +17,9 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
+
+/************************** Types and definitions ***************************/
 
 #define SILC_IS_SOCKET_STREAM(s) (s->ops == &silc_socket_stream_ops)
 
@@ -42,6 +44,9 @@ typedef struct {
   unsigned int aborted      : 1;
 } *SilcSocketHostLookup;
 
+
+/************************ Static utility functions **************************/
+
 /* The IO process callback that calls the notifier callback to upper
    layer. */
 
@@ -94,16 +99,6 @@ SILC_TASK_CALLBACK(silc_socket_host_lookup_finish)
     stream = lookup->stream = NULL;
   }
 
-  /* Add the socket to scheduler */
-  if (stream) {
-    silc_schedule_task_add_fd(stream->schedule, stream->sock,
-                             silc_socket_stream_io, stream);
-
-    /* Initially set socket for reading */
-    silc_schedule_set_listen_fd(stream->schedule, stream->sock,
-                               SILC_TASK_READ, FALSE);
-  }
-
   /* Return the created socket stream to the caller */
   if (lookup->callback)
     lookup->callback(lookup->status, stream, lookup->context);
@@ -163,6 +158,9 @@ static void silc_socket_host_lookup_abort(SilcAsyncOperation op,
   lookup->aborted = TRUE;
 }
 
+
+/******************************* Public API *********************************/
+
 /* Creates socket stream */
 
 SilcAsyncOperation
@@ -228,8 +226,8 @@ silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn,
 /* Returns socket stream information */
 
 SilcBool silc_socket_stream_get_info(SilcStream stream,
-                                int *sock, const char **hostname,
-                                const char **ip, SilcUInt16 *port)
+                                    int *sock, const char **hostname,
+                                    const char **ip, SilcUInt16 *port)
 {
   SilcSocketStream socket_stream = stream;
 
@@ -251,8 +249,8 @@ SilcBool silc_socket_stream_get_info(SilcStream stream,
 /* Set socket information */
 
 SilcBool silc_socket_stream_set_info(SilcStream stream,
-                                const char *hostname,
-                                const char *ip, SilcUInt16 port)
+                                    const char *hostname,
+                                    const char *ip, SilcUInt16 port)
 {
   SilcSocketStream socket_stream = stream;
 
@@ -292,10 +290,10 @@ int silc_socket_stream_get_error(SilcStream stream)
 /* Set QoS for socket stream */
 
 SilcBool silc_socket_stream_set_qos(SilcStream stream,
-                               SilcUInt32 read_rate,
-                               SilcUInt32 read_limit_bytes,
-                               SilcUInt32 limit_sec,
-                               SilcUInt32 limit_usec)
+                                   SilcUInt32 read_rate,
+                                   SilcUInt32 read_limit_bytes,
+                                   SilcUInt32 limit_sec,
+                                   SilcUInt32 limit_usec)
 {
   SilcSocketStream socket_stream = stream;
 
@@ -362,6 +360,7 @@ void silc_socket_stream_destroy(SilcStream stream)
   silc_socket_stream_close(socket_stream);
   silc_free(socket_stream->ip);
   silc_free(socket_stream->hostname);
+  silc_schedule_task_del_by_fd(socket_stream->schedule, socket_stream->sock);
 
   if (socket_stream->qos) {
     silc_schedule_task_del_by_context(socket_stream->schedule,
@@ -380,6 +379,7 @@ void silc_socket_stream_destroy(SilcStream stream)
 /* Sets stream notification callback for the stream */
 
 void silc_socket_stream_notifier(SilcStream stream,
+                                SilcSchedule schedule,
                                 SilcStreamNotifier callback,
                                 void *context)
 {
@@ -392,6 +392,35 @@ void silc_socket_stream_notifier(SilcStream stream,
 
   socket_stream->notifier = callback;
   socket_stream->notifier_context = context;
+  socket_stream->schedule = schedule;
+
+  if (socket_stream->notifier) {
+    /* Add the socket to scheduler.  Safe to call if already added. */
+    silc_schedule_task_add_fd(socket_stream->schedule, socket_stream->sock,
+                             silc_socket_stream_io, socket_stream);
+
+    /* Initially set socket for reading */
+    silc_schedule_set_listen_fd(socket_stream->schedule, socket_stream->sock,
+                               SILC_TASK_READ, FALSE);
+  } else {
+    /* Unschedule the socket */
+    silc_schedule_unset_listen_fd(socket_stream->schedule,
+                                 socket_stream->sock);
+    silc_schedule_task_del_by_fd(socket_stream->schedule,
+                                socket_stream->sock);
+  }
+}
+
+/* Return associated scheduler */
+
+SilcSchedule silc_socket_stream_get_schedule(SilcStream stream)
+{
+  SilcSocketStream socket_stream = stream;
+
+  if (!SILC_IS_SOCKET_STREAM(socket_stream))
+    return NULL;
+
+  return socket_stream->schedule;
 }
 
 /* SILC Socket Stream ops.  Functions are implemented under the
@@ -403,4 +432,5 @@ const SilcStreamOps silc_socket_stream_ops =
   silc_socket_stream_close,
   silc_socket_stream_destroy,
   silc_socket_stream_notifier,
+  silc_socket_stream_get_schedule,
 };
index 565190966b9eba97198fa2227c4a787aa9a3f141..a83a44b7963ba9e80fde1978d117dbf98307c4b5 100644 (file)
@@ -85,7 +85,8 @@ typedef void (*SilcSocketStreamCallback)(SilcSocketStreamStatus status,
  * SYNOPSIS
  *
  *    SilcAsyncOperation
- *    silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn,
+ *    silc_socket_stream_create(int sock, SilcBool lookup,
+ *                              SilcBool require_fqdn,
  *                              SilcSchedule schedule,
  *                              SilcSocketStreamCallback callback,
  *                              void *context);
@@ -110,7 +111,8 @@ typedef void (*SilcSocketStreamCallback)(SilcSocketStreamStatus status,
  *
  ***/
 SilcAsyncOperation
-silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn,
+silc_socket_stream_create(int sock, SilcBool lookup,
+                         SilcBool require_fqdn,
                          SilcSchedule schedule,
                          SilcSocketStreamCallback callback,
                          void *context);
@@ -132,8 +134,8 @@ silc_socket_stream_create(int sock, SilcBool lookup, SilcBool require_fqdn,
  *
  ***/
 SilcBool silc_socket_stream_get_info(SilcStream stream,
-                                int *sock, const char **hostname,
-                                const char **ip, SilcUInt16 *port);
+                                    int *sock, const char **hostname,
+                                    const char **ip, SilcUInt16 *port);
 
 /****f* silcutil/SilcSocketStreamAPI/silc_socket_stream_set_info
  *
@@ -156,8 +158,8 @@ SilcBool silc_socket_stream_get_info(SilcStream stream,
  *
  ***/
 SilcBool silc_socket_stream_set_info(SilcStream stream,
-                                const char *hostname,
-                                const char *ip, SilcUInt16 port);
+                                    const char *hostname,
+                                    const char *ip, SilcUInt16 port);
 
 /****f* silcutil/SilcSocketStreamAPI/silc_socket_stream_get_error
  *
@@ -178,10 +180,10 @@ int silc_socket_stream_get_error(SilcStream stream);
  * SYNOPSIS
  *
  *    SilcBool silc_socket_stream_set_qos(SilcStream stream,
- *                                    SilcUInt32 read_rate,
- *                                    SilcUInt32 read_limit_bytes,
- *                                    SilcUInt32 limit_sec,
- *                                    SilcUInt32 limit_usec)
+ *                                        SilcUInt32 read_rate,
+ *                                        SilcUInt32 read_limit_bytes,
+ *                                        SilcUInt32 limit_sec,
+ *                                        SilcUInt32 limit_usec)
  *
  * DESCRIPTION
  *
@@ -198,10 +200,10 @@ int silc_socket_stream_get_error(SilcStream stream);
  *
  ***/
 SilcBool silc_socket_stream_set_qos(SilcStream stream,
-                               SilcUInt32 read_rate,
-                               SilcUInt32 read_limit_bytes,
-                               SilcUInt32 limit_sec,
-                               SilcUInt32 limit_usec);
+                                   SilcUInt32 read_rate,
+                                   SilcUInt32 read_limit_bytes,
+                                   SilcUInt32 limit_sec,
+                                   SilcUInt32 limit_usec);
 
 #include "silcsocketstream_i.h"
 
index 387f0a263d7efe0a26654d304c0fb6064815fbac..0e4b67de83c38cfabf51c4fd698319e134fe2c57 100644 (file)
@@ -19,7 +19,7 @@
 
 /* #define SILC_STACK_DEBUG 1 */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Allocate the stack */
 
@@ -258,7 +258,8 @@ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size,
 
   /* Align the old size if needed */
   old_size = (aligned ?
-             SILC_STACK_ALIGN(old_size, SILC_STACK_DEFAULT_ALIGN) : old_size);
+             SILC_STACK_ALIGN(old_size,
+                              SILC_STACK_DEFAULT_ALIGN) : old_size);
 
   /* Compute the size of current stack block */
   bsize = SILC_STACK_BLOCK_SIZE(stack, si);
@@ -275,7 +276,8 @@ void *silc_stack_realloc(SilcStack stack, SilcUInt32 old_size,
   /* Now check that the new size fits to this block */
   if (stack->stack[si]->bytes_left >= size) {
     /* It fits, so simply return the old pointer */
-    size = (aligned ? SILC_STACK_ALIGN(size, SILC_STACK_DEFAULT_ALIGN) : size);
+    size = (aligned ? SILC_STACK_ALIGN(size,
+                                      SILC_STACK_DEFAULT_ALIGN) : size);
     stack->stack[si]->bytes_left -= (size - old_size);
     SILC_STACK_STAT(stack, bytes_malloc, (size - old_size));
     return ptr;
index ca293fca1848c59440159a1c59bfbbd32a60bc10..730ce55cb0ab742f75c819f20cd9dac0fc07f972 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 typedef struct {
   SilcStreamOps *ops;
@@ -49,9 +49,15 @@ void silc_stream_destroy(SilcStream stream)
   return h->ops->destroy(stream);
 }
 
-void silc_stream_set_notifier(SilcStream stream, SilcStreamNotifier notifier,
-                             void *context)
+void silc_stream_set_notifier(SilcStream stream, SilcSchedule schedule,
+                             SilcStreamNotifier notifier, void *context)
 {
   SilcStreamHeader h = stream;
-  return h->ops->notifier(stream, notifier, context);
+  return h->ops->notifier(stream, schedule, notifier, context);
+}
+
+SilcSchedule silc_stream_get_schedule(SilcStream stream)
+{
+  SilcStreamHeader h = stream;
+  return h->ops->get_schedule(stream);
 }
index e3278ab30ba260870cf2f4f2f83e2342d2be52c3..e6570e4574f2d5329f198cf228da264b07e2f924 100644 (file)
@@ -144,10 +144,16 @@ typedef struct {
      silc_stream_destroy function was called. */
   void (*destroy)(SilcStream stream);
 
-  /* This is called to set a notifier callback to the stream.  This is
-     called when silc_stream_set_notifier was called. */
-  void (*notifier)(SilcStream stream, SilcStreamNotifier callback,
-                  void *context);
+  /* This is called to set a notifier callback to the stream and schedule
+     the stream.  Stream should not be scheduled before calling this
+     function.  If stream does not need scheduler then the scheduler can
+     be ignored.  This is called when silc_stream_set_notifier was called. */
+  void (*notifier)(SilcStream stream, SilcSchedule schedule,
+                  SilcStreamNotifier callback, void *context);
+
+  /* This is called to return the associated scheduler, if set.  This is
+     called when silc_stream_get_schedule was called. */
+  SilcSchedule (*get_schedule)(SilcStream stream);
 } SilcStreamOps;
 /***/
 
@@ -229,19 +235,37 @@ void silc_stream_destroy(SilcStream stream);
  * SYNOPSIS
  *
  *    void silc_stream_set_notifier(SilcStream stream,
+ *                                  SilcSchedule schedule,
  *                                  SilcStreamNotifier notifier,
  *                                  void *context);
  *
  * DESCRIPTION
  *
  *    Set a notifier callback for the stream indicated by `stream' to be called
- *    when some action takes place on the stream.  It is called for example
- *    when data is available for reading or writing, or if an error occurs.
- *    This can be called at any time for valid stream.  If `notifier' is set
- *    to NULL no callback will be called for the stream.
+ *    when some action takes place on the stream.  This effectively means
+ *    scheduling the stream for various actions, that then eventually will
+ *    be delivered to caller in the `notifier'  callback.  It is called for
+ *    example when data is available for reading or writing, or if an error
+ *    occurs.  This can be called at any time for valid stream.
+ *    If `notifier' is set to NULL no callback will be called for the stream,
+ *    and the stream is not scheduled anymore.
+ *
+ ***/
+void silc_stream_set_notifier(SilcStream stream, SilcSchedule schedule,
+                             SilcStreamNotifier notifier, void *context);
+
+/****f* silcutil/SilcStreamAPI/silc_stream_get_schedule
+ *
+ * SYNOPSIS
+ *
+ *    SilcSchedule silc_stream_get_schedule(SilcStream stream);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the scheduler that has been associated with the `stream', or
+ *    NULL if one has not been set for the `stream'.
  *
  ***/
-void silc_stream_set_notifier(SilcStream stream, SilcStreamNotifier notifier,
-                             void *context);
+SilcSchedule silc_stream_get_schedule(SilcStream stream);
 
 #endif /* SILCSTREAM_H */
index aa2119e5208898971ff06ed821dbd20b1a5f47d6..5674eaf3009226abb2fff24ebb87b6b4a0ae7197 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcstringprep.h"
 #include <stringprep.h>
 
index 8fddd0b22a7ebdebdeabbfbcd54cebce110eb3fb..fadd31174069a4c6eb49adbb51c45d52e01f6ceb 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcstrutil.h"
 
 static unsigned char pem_enc[64] =
@@ -170,88 +170,6 @@ unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
   return data;
 }
 
-/* Mime constants and macros */
-#define MIME_VERSION "MIME-Version: "
-#define MIME_VERSION_LEN 14
-#define MIME_CONTENT_TYPE "Content-Type: "
-#define MIME_CONTENT_TYPE_LEN 14
-#define MIME_TRANSFER_ENCODING "Content-Transfer-Encoding: "
-#define MIME_TRANSFER_ENCODING_LEN 27
-
-#define MIME_GET_FIELD(mime, mime_len, field, field_len,               \
-                      dest, dest_size)                                 \
-do {                                                                   \
-  if (dest) {                                                          \
-    char *f = strstr(mime, field);                                     \
-    if (f) {                                                           \
-      int parse_len;                                                   \
-      f += field_len;                                                  \
-      parse_len = (mime_len - (f - (char *)mime));                     \
-      for (i = 0; i < parse_len; i++) {                                        \
-        if ((i == dest_size) ||                                                \
-           ((f[i] == '\n') &&                                          \
-              ((i == parse_len - 1) ||                                 \
-                 ((f[i+1] != ' ') && (f[i+1] != '\t')))) ||            \
-           ((f[i] == '\r') &&                                          \
-              ((i == parse_len - 1) || (f[i+1] == '\n')) &&            \
-              ((i >= parse_len - 2) ||                                 \
-                 ((f[i+2] != ' ') && (f[i+2] != '\t')))))              \
-          break;                                                       \
-        dest[i] = f[i];                                                        \
-      }                                                                        \
-    }                                                                  \
-  }                                                                    \
-} while(0)
-
-/* Parses MIME object and MIME header in it. */
-
-SilcBool
-silc_mime_parse(const unsigned char *mime, SilcUInt32 mime_len,
-                char *version, SilcUInt32 version_size,
-                char *content_type, SilcUInt32 content_type_size,
-                char *transfer_encoding, SilcUInt32 transfer_encoding_size,
-                unsigned char **mime_data_ptr, SilcUInt32 *mime_data_len)
-{
-  int i;
-  unsigned char *tmp;
-
-  /* Get the pointer to the data area in the object */
-  for (i = 0; i < mime_len; i++) {
-    if ((mime_len >= i + 4 &&
-        mime[i    ] == '\r' && mime[i + 1] == '\n' &&
-        mime[i + 2] == '\r' && mime[i + 3] == '\n') ||
-       (mime_len >= i + 2 &&
-        mime[i    ] == '\n' && mime[i + 1] == '\n'))
-      break;
-  }
-  if (i >= mime_len)
-    return FALSE;
-
-  if (mime_data_ptr)
-    *mime_data_ptr = (unsigned char *)mime + i +
-           (mime[i] == '\n' ? 2 : 4);
-  if (mime_data_len)
-    *mime_data_len = mime_len - (i + (mime[i] == '\n' ? 2 : 4));
-
-  /* Check for mandatory Content-Type field */
-  tmp = strstr(mime, MIME_CONTENT_TYPE);
-  if (!tmp || (tmp - mime) >= i)
-    return FALSE;
-
-  /* Get MIME version, Content-Type and Transfer Encoding fields */
-  MIME_GET_FIELD(mime, mime_len,
-                MIME_VERSION, MIME_VERSION_LEN,
-                version, version_size);
-  MIME_GET_FIELD(mime, mime_len,
-                MIME_CONTENT_TYPE, MIME_CONTENT_TYPE_LEN,
-                content_type, content_type_size);
-  MIME_GET_FIELD(mime, mime_len,
-                MIME_TRANSFER_ENCODING, MIME_TRANSFER_ENCODING_LEN,
-                transfer_encoding, transfer_encoding_size);
-
-  return TRUE;
-}
-
 /* Concatenates the `src' into `dest'.  If `src_len' is more than the
    size of the `dest' (minus NULL at the end) the `src' will be
    truncated to fit. */
index 23451d50c3ab86aaf59597a585f27b6967b93d7b..3d96492f9169ca2231a420c79068fcefe48140d7 100644 (file)
@@ -111,45 +111,6 @@ char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len);
 unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
                               SilcUInt32 *ret_len);
 
-/****f* silcutil/SilcStrUtilAPI/silc_mime_parse
- *
- * SYNOPSIS
- *
- *    SilcBool
- *    silc_mime_parse(const unsigned char *mime, SilcUInt32 mime_len,
- *                    char *version, SilcUInt32 version_size,
- *                    char *content_type, SilcUInt32 content_type_size,
- *                    char *transfer_encoding,
- *                    SilcUInt32 transfer_encoding_size,
- *                    unsigned char **mime_data_ptr,
- *                    SilcUInt32 *mime_data_len);
- *
- * DESCRIPTION
- *
- *    Parses MIME header indicated by `mime' data block of length of
- *    `mime_len'.  Returns TRUE if the `mime' is valid MIME object.
- *    Parses from the MIME header the MIME Version (if present) and
- *    copies it to the `version' pointer if provided, content type
- *    indicating the data in the MIME object and copies it to the
- *    `content_type' if provided, and the tranfer encoding (if present)
- *    indicating the encoding of the data and copies it to the
- *    `content_transfer_encoding' if provided.
- *
- *    The pointer to the actual data in the MIME object is saved into
- *    `mime_data_ptr'.  The pointer is a location in the `mime' and it
- *    does not allocate or copy anything, ie. the `mime_data_ptr' is a
- *    pointer to the `mime'.  The `mime_data_len' indicates the length of
- *    the data without the MIME header.  The caller is responsible of
- *    NULL terminating the buffers it provides.
- *
- ***/
-SilcBool
-silc_mime_parse(const unsigned char *mime, SilcUInt32 mime_len,
-                char *version, SilcUInt32 version_size,
-                char *content_type, SilcUInt32 content_type_size,
-                char *transfer_encoding, SilcUInt32 transfer_encoding_size,
-                unsigned char **mime_data_ptr, SilcUInt32 *mime_data_len);
-
 /****f* silcutil/SilcStrUtilAPI/silc_strncat
  *
  * SYNOPSIS
@@ -182,14 +143,14 @@ char *silc_strncat(char *dest, SilcUInt32 dest_size,
  *
  *    Checks that the 'identifier' string is valid identifier string
  *    and does not contain any unassigned or prohibited character.  This
- *    function is used to check for valid nicknames, server names, 
- *    usernames, hostnames, service names, algorithm names, other security 
+ *    function is used to check for valid nicknames, server names,
+ *    usernames, hostnames, service names, algorithm names, other security
  *    property names, and SILC Public Key name.
  *
  *    If the 'max_allowed_length' is non-zero the identifier cannot be
  *    longer than that, and NULL is returned if it is.  If zero (0), no
  *    length limit exist.  For nicknames the max length must be 128 bytes.
- *    Other identifiers has no default limit, but application may choose 
+ *    Other identifiers has no default limit, but application may choose
 *     one anyway.
  *
  *    Returns the validated string, that the caller must free.  Returns
@@ -227,14 +188,14 @@ unsigned char *silc_identifier_check(const unsigned char *identifier,
  *
  *    Checks that the 'identifier' string is valid identifier string
  *    and does not contain any unassigned or prohibited character.  This
- *    function is used to check for valid nicknames, server names, 
- *    usernames, hostnames, service names, algorithm names, other security 
+ *    function is used to check for valid nicknames, server names,
+ *    usernames, hostnames, service names, algorithm names, other security
  *    property names, and SILC Public Key name.
  *
  *    If the 'max_allowed_length' is non-zero the identifier cannot be
  *    longer than that, and NULL is returned if it is.  If zero (0), no
  *    length limit exist.  For nicknames the max length must be 128 bytes.
- *    Other identifiers has no default limit, but application may choose 
+ *    Other identifiers has no default limit, but application may choose
  *    one anyway.
  *
  *    Returns TRUE if the string is valid and FALSE if it is prohibited.
index 9eb3ae43b1bbb9be3197215464c03e7f790d2123..13575e57ee62132c5ebdb8f1e592a7216e4b5879 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Return time since Epoch */
 
@@ -92,12 +92,12 @@ SilcBool silc_time_value(SilcInt64 timeval, SilcTime ret_time)
 /* Fills the SilcTime structure with correct values */
 
 static SilcBool silc_time_fill(SilcTime time,
-                          unsigned int year,
-                          unsigned int month,
-                          unsigned int day,
-                          unsigned int hour,
-                          unsigned int minute,
-                          unsigned int second)
+                              unsigned int year,
+                              unsigned int month,
+                              unsigned int day,
+                              unsigned int hour,
+                              unsigned int minute,
+                              unsigned int second)
 {
   if (year > 8191)
     return FALSE;
@@ -181,7 +181,7 @@ SilcBool silc_time_universal(const char *universal_time, SilcTime ret_time)
 /* Encode universal time string. */
 
 SilcBool silc_time_universal_string(SilcTime timeval, char *ret_string,
-                               SilcUInt32 ret_string_size)
+                                   SilcUInt32 ret_string_size)
 {
   int ret, len = 0;
   memset(ret_string, 0, ret_string_size);
@@ -291,7 +291,7 @@ SilcBool silc_time_generalized(const char *generalized_time, SilcTime ret_time)
 /* Encode generalized time string */
 
 SilcBool silc_time_generalized_string(SilcTime timeval, char *ret_string,
-                                 SilcUInt32 ret_string_size)
+                                     SilcUInt32 ret_string_size)
 {
   int len = 0, ret;
   memset(ret_string, 0, ret_string_size);
index 5b21aa7f0cecfefb5f213438227c244db5b1b09b..47890ee5fc9ee660d9fc0f1dfe0f6e33a3a87c90 100644 (file)
@@ -136,7 +136,7 @@ SilcBool silc_time_universal(const char *universal_time, SilcTime ret_time);
  * SYNOPSIS
  *
  *    SilcBool silc_time_universal_string(SilcTime timeval, char *ret_string,
- *                                    SilcUInt32 ret_string_size);
+ *                                        SilcUInt32 ret_string_size);
  *
  * DESCRIPTION
  *
@@ -145,14 +145,14 @@ SilcBool silc_time_universal(const char *universal_time, SilcTime ret_time);
  *
  ***/
 SilcBool silc_time_universal_string(SilcTime timeval, char *ret_string,
-                               SilcUInt32 ret_string_size);
+                                   SilcUInt32 ret_string_size);
 
 /****f* silcutil/SilcTimeAPI/silc_time_generalized
  *
  * SYNOPSIS
  *
  *    SilcBool silc_time_generalized(const char *generalized_time,
- *                               SilcTime ret_time);
+ *                                   SilcTime ret_time);
  *
  * DESCRIPTION
  *
@@ -175,14 +175,15 @@ SilcBool silc_time_universal_string(SilcTime timeval, char *ret_string,
  *    silc_time_generalized("20030219190510.212Z", &ret_time);
  *
  ***/
-SilcBool silc_time_generalized(const char *generalized_time, SilcTime ret_time);
+SilcBool
+silc_time_generalized(const char *generalized_time, SilcTime ret_time);
 
 /****f* silcutil/SilcTimeAPI/silc_time_generalized_string
  *
  * SYNOPSIS
  *
  *    SilcBool silc_time_generalized_string(SilcTime timeval, char *ret_string,
- *                                      SilcUInt32 ret_string_size);
+ *                                          SilcUInt32 ret_string_size);
  *
  * DESCRIPTION
  *
@@ -191,6 +192,6 @@ SilcBool silc_time_generalized(const char *generalized_time, SilcTime ret_time);
  *
  ***/
 SilcBool silc_time_generalized_string(SilcTime timeval, char *ret_string,
-                                 SilcUInt32 ret_string_size);
+                                     SilcUInt32 ret_string_size);
 
 #endif /* SILCTIME_H */
index 9b3645586057bfa9a07eca28da71bf0e6b178a39..cffbf2e17db3812eaee93d8dd08ff805483a9d2a 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcutf8.h"
 
 /* Encodes the string `bin' of which encoding is `bin_encoding' to the
index b4472bebe38b2a018b7d80aa5a5b51c25b6fa773..86b2f850b3546b99cdfb13bba8c901881b2511db 100644 (file)
@@ -22,7 +22,7 @@
  */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
    This doesn't remove the newline sign from the destination buffer. The
@@ -129,37 +129,47 @@ SilcBool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
 
 /* Parse userfqdn string which is in user@fqdn format. */
 
-SilcBool silc_parse_userfqdn(const char *string, char **left, char **right)
+int silc_parse_userfqdn(const char *string,
+                       char *user, SilcUInt32 user_size,
+                       char *fqdn, SilcUInt32 fqdn_size)
 {
   SilcUInt32 tlen;
 
-  if (!string)
-    return FALSE;
+  if (!string || (!user && !fqdn))
+    return 0;
 
   if (string[0] == '@') {
-    if (left)
-      *left = strdup(string);
-    return TRUE;
+    if (user) {
+      memset(user, 0, user_size);
+      silc_strncat(user, user_size, string, strlen(string));
+    }
+
+    return 1;
   }
 
   if (strchr(string, '@')) {
     tlen = strcspn(string, "@");
 
-    if (left) {
-      *left = silc_calloc(tlen + 1, sizeof(char));
-      memcpy(*left, string, tlen);
+    if (user) {
+      memset(user, 0, user_size);
+      silc_strncat(user, user_size, string, tlen);
     }
 
-    if (right) {
-      *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
-      memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
+    if (fqdn) {
+      memset(fqdn, 0, fqdn_size);
+      silc_strncat(fqdn, fqdn_size, string + tlen + 1,
+                  strlen(string) - tlen - 1);
     }
-  } else {
-    if (left)
-      *left = silc_memdup(string, strlen(string));
+
+    return 2;
   }
 
-  return TRUE;
+  if (user) {
+    memset(user, 0, user_size);
+    silc_strncat(user, user_size, string, strlen(string));
+  }
+
+  return 1;
 }
 
 /* Parses command line. At most `max_args' is taken. Rest of the line
@@ -243,7 +253,7 @@ void silc_parse_command_line(unsigned char *buffer,
 char *silc_format(char *fmt, ...)
 {
   va_list args;
-  static char buf[8192];
+  char buf[8192];
 
   memset(buf, 0, sizeof(buf));
   va_start(args, fmt);
@@ -613,6 +623,14 @@ SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
          SILC_ID_COMPARE_TYPE(key1, key2, id_type));
 }
 
+/* Compares two ID's. Compares full IDs. */
+
+SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
+{
+  SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
+  return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
+}
+
 /* Compare two Client ID's entirely and not just the hash from the ID. */
 
 SilcBool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
@@ -634,8 +652,8 @@ SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
 {
   int l1 = strlen((char *)key1);
   int l2 = strlen((char *)key2);
-  if (l1 > l2)
-    l2 = l1;
+  if (l1 != l2)
+    return FALSE;
   return !memcmp(key1, key2, l2);
 }
 
@@ -816,11 +834,11 @@ SilcBool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
 /* Parses SILC protocol style version string. */
 
 SilcBool silc_parse_version_string(const char *version,
-                              SilcUInt32 *protocol_version,
-                              char **protocol_version_string,
-                              SilcUInt32 *software_version,
-                              char **software_version_string,
-                              char **vendor_version)
+                                  SilcUInt32 *protocol_version,
+                                  char **protocol_version_string,
+                                  SilcUInt32 *software_version,
+                                  char **software_version_string,
+                                  char **vendor_version)
 {
   char *cp, buf[32];
   int maj = 0, min = 0;
index 4ab331427992c7422565f24caa4324922ef699f8..1e2a68eacfcabe8c3b34b38f04b4b0a044a3bdd4 100644 (file)
@@ -104,14 +104,20 @@ SilcBool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size);
  *
  * SYNOPSIS
  *
- *    SilcBool silc_parse_userfqdn(const char *string, char **left, char **right);
+ *    int silc_parse_userfqdn(const char *string,
+ *                            char *user, SilcUInt32 user_size,
+ *                            char *fqdn, SilcUInt32 fqdn_size);
  *
  * DESCRIPTION
  *
- *    Parse userfqdn string which is in user@fqdn format.
+ *    Parse userfqdn string which is in user@fqdn format.  Returns 0 on
+ *    error, 1 if `user' was filled and 2 if both `user' and `fqdn'
+ *    was filled.
  *
  ***/
-SilcBool silc_parse_userfqdn(const char *string, char **left, char **right);
+int silc_parse_userfqdn(const char *string,
+                       char *user, SilcUInt32 user_size,
+                       char *fqdn, SilcUInt32 fqdn_size);
 
 /****f* silcutil/SilcUtilAPI/silc_parse_command_line
  *
@@ -308,7 +314,8 @@ SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context);
  *
  * SYNOPSIS
  *
- *    SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context);
+ *    SilcBool silc_hash_id_compare(void *key1, void *key2,
+ *                                  void *user_context);
  *
  * DESCRIPTION
  *
@@ -319,24 +326,43 @@ SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context);
  ***/
 SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context);
 
+/****f* silcutil/SilcUtilAPI/silc_hash_id_compare_full
+ *
+ * SYNOPSIS
+ *
+ *    SilcBool silc_hash_id_compare_full(void *key1, void *key2,
+ *                                       void *user_context)
+ *
+ * DESCRIPTION
+ *
+ *    Compares two ID's. May be used as SilcHashTable comparison function.
+ *    To compare full ID's instead of only partial, like the
+ *    silc_hash_id_compare does, use this function.
+ *
+ ***/
+SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context);
+
 /****f* silcutil/SilcUtilAPI/silc_hash_client_id_compare
  *
  * SYNOPSIS
  *
- *    SilcBool silc_hash_client_id_compare(void *key1, void *key2, void *user_context);
+ *    SilcBool silc_hash_client_id_compare(void *key1, void *key2,
+ *                                         void *user_context);
  *
  * DESCRIPTION
  *
  *    Compare two Client ID's entirely and not just the hash from the ID.
  *
  ***/
-SilcBool silc_hash_client_id_compare(void *key1, void *key2, void *user_context);
+SilcBool silc_hash_client_id_compare(void *key1, void *key2,
+                                    void *user_context);
 
 /****f* silcutil/SilcUtilAPI/silc_hash_data_compare
  *
  * SYNOPSIS
  *
- *    SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context);
+ *    SilcBool silc_hash_data_compare(void *key1, void *key2,
+ *                                    void *user_context);
  *
  * DESCRIPTION
  *
@@ -349,7 +375,8 @@ SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context);
  *
  * SYNOPSIS
  *
- *    SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context);
+ *    SilcBool silc_hash_utf8_compare(void *key1, void *key2,
+ *                                    void *user_context);
  *
  * DESCRIPTION
  *
@@ -364,7 +391,7 @@ SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context);
  * SYNOPSIS
  *
  *    SilcBool silc_hash_public_key_compare(void *key1, void *key2,
- *                                      void *user_context);
+ *                                          void *user_context);
  *
  * DESCRIPTION
  *
@@ -372,7 +399,8 @@ SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context);
  *    comparison function.
  *
  ***/
-SilcBool silc_hash_public_key_compare(void *key1, void *key2, void *user_context);
+SilcBool silc_hash_public_key_compare(void *key1, void *key2,
+                                     void *user_context);
 
 /****f* silcutil/SilcUtilAPI/silc_client_chmode
  *
index 4509f28078aba26e16c94a9b16c229cdd2a55fb6..dad057e1f3a038671e8c2b6c67adce3d1672940f 100644 (file)
@@ -19,7 +19,7 @@
 /* $Id$ */
 /* Implementation of the VCard (RFC 2426) */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #define VCARD_HEADER "BEGIN:VCARD\n"
 #define VCARD_VERSION "VERSION:3.0\n"
index c4bf086af63b3bc760d92d32571d6e11a8aaeae0..1a93192647fb7623deba80a6d136677701cbc05a 100644 (file)
@@ -17,7 +17,7 @@
 
 */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifdef SILC_STACKTRACE
 
index 0e11b868362517491b9f14352a7e227d2cb1ac97..0a1fecc8a1478d55a1cdebf68ea0c0de3868c865 100644 (file)
@@ -1,6 +1,6 @@
 /* SilcAsyncOperation tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcfsm.h"
 #include "silcasync.h"
 
@@ -80,14 +80,17 @@ SILC_FSM_STATE(test_st_start)
 SILC_FSM_STATE(test_st_second)
 {
   Foo f = fsm_context;
+  SilcBool timedout;
 
   SILC_LOG_DEBUG(("test_st_second"));
 
-  SILC_FSM_SEMA_TIMEDWAIT(&f->sema, 0, 1);
+  SILC_FSM_SEMA_TIMEDWAIT(&f->sema, 0, 1, &timedout);
 
-  SILC_LOG_DEBUG(("Sema timedout, aborting async operation"));
-  if (f->op)
-    silc_async_abort(f->op, NULL, NULL);
+  if (timedout == TRUE) {
+    SILC_LOG_DEBUG(("Sema timedout, aborting async operation"));
+    if (f->op)
+      silc_async_abort(f->op, NULL, NULL);
+  }
 
   /** Finish */
   silc_fsm_next_later(fsm, test_st_finish, 2, 0);
index dcdccdd471574ce34b94b05a8194835470ccb2d1..fad7a6dd670680edf647550134056148b5da9a14 100644 (file)
@@ -1,6 +1,6 @@
 /* SILC FD Stream tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 SilcBool success = FALSE;
 SilcSchedule schedule;
@@ -58,13 +58,13 @@ SILC_FSM_STATE(st_readwrite)
   }
 
   SILC_LOG_DEBUG(("Creating FD stream (two fds)"));
-  stream = silc_fd_stream_create2(fd1, fd2, schedule);
+  stream = silc_fd_stream_create2(fd1, fd2);
   if (!stream) {
     SILC_LOG_DEBUG(("Error creating stream"));
     goto err;
   }
 
-  silc_stream_set_notifier(stream, stream_notifier2, fsm);
+  silc_stream_set_notifier(stream, schedule, stream_notifier2, fsm);
 
   /* Stream between the fiels */
   SILC_LOG_DEBUG(("Read/write 3 bytes at a time"));
@@ -115,7 +115,7 @@ SILC_FSM_STATE(st_readwrite)
     SILC_LOG_DEBUG(("Destroying stream"));
     silc_stream_destroy(stream);
   }
+
   silc_fsm_next(fsm, st_end);
   return SILC_FSM_CONTINUE;
 
@@ -126,27 +126,20 @@ SILC_FSM_STATE(st_readwrite)
 
 SILC_FSM_STATE(st_write)
 {
-  int ret, i, k, fd;
+  int ret, i, k;
   char *cp;
 
   /* Simple writing example */
   SILC_LOG_DEBUG(("Open file /tmp/test_silcfdstream for writing"));
-
-  unlink("/tmp/test_silcfdstream");
-  fd = silc_file_open("/tmp/test_silcfdstream", O_CREAT | O_RDWR);
-  if (fd < 0) {
-    SILC_LOG_DEBUG(("Error opening file"));
-    goto err;
-  }
-
   SILC_LOG_DEBUG(("Creating FD stream"));
-  stream = silc_fd_stream_create(fd, schedule);
+  unlink("/tmp/test_silcfdstream");
+  stream = silc_fd_stream_file("/tmp/test_silcfdstream", FALSE, TRUE);
   if (!stream) {
     SILC_LOG_DEBUG(("Error creating stream"));
     goto err;
   }
 
-  silc_stream_set_notifier(stream, stream_notifier, fsm);
+  silc_stream_set_notifier(stream, schedule, stream_notifier, fsm);
 
   memset(buf1, 0, sizeof(buf1));
   for (i = 0; i < sizeof(buf1); i++)
index be2cd48d9a2a2322767d5aaa691bfd33c9bc7be8..c801a5e0187bf3e4627489263953d7afdddbc33c 100644 (file)
@@ -1,6 +1,6 @@
 /* SILC FSM tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcfsm.h"
 
 typedef void (*Callback)(void *context);
@@ -116,14 +116,9 @@ SILC_FSM_STATE(test_st_fourth)
   f->timeout = 1;
 
   SILC_LOG_DEBUG(("Creating FSM thread"));
-  if (!silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, FALSE)) {
-    /** Error creating thread */
-    SILC_LOG_DEBUG(("Error creating thread"));
-    f->error = TRUE;
-    silc_fsm_next(fsm, test_st_finish);
-    return SILC_FSM_CONTINUE;
-  }
+  silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, FALSE);
   SILC_LOG_DEBUG(("Starting thread"));
+  /*** Start thread */
   silc_fsm_start(&f->thread, test_thread_st_start);
 
   /** Waiting thread to terminate */
@@ -165,20 +160,14 @@ SILC_FSM_STATE(test_st_fifth)
   silc_fsm_sema_init(&f->sema, fsm, 0);
 
   SILC_LOG_DEBUG(("Creating FSM thread"));
-  if (!silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, TRUE)) {
-    /** Error creating real thread */
-    SILC_LOG_DEBUG(("Error creating thread"));
-    f->error = TRUE;
-    silc_fsm_next(fsm, test_st_finish);
-    return SILC_FSM_CONTINUE;
-  }
+  silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, TRUE);
   SILC_LOG_DEBUG(("Starting thread"));
   silc_fsm_start(&f->thread, test_thread2_st_start);
 
   /** Waiting thread to terminate, timeout */
   SILC_LOG_DEBUG(("Waiting for thread to terminate for 5 seconds"));
   silc_fsm_next(fsm, test_st_sixth);
-  SILC_FSM_SEMA_TIMEDWAIT(&f->sema, 5, 0);
+  SILC_FSM_SEMA_TIMEDWAIT(&f->sema, 5, 0, NULL);
   return SILC_FSM_CONTINUE;
 }
 
@@ -247,15 +236,8 @@ SILC_FSM_STATE(test_st_seventh)
     f->threads[i].rounds = 10;
     f->threads[i].f = f;
     silc_fsm_sema_init(&f->threads[i].sema, fsm, 0);
-    if (!silc_fsm_thread_init(&f->threads[i].thread, fsm,
-                             &f->threads[i], NULL, NULL, FALSE)) {
-      /** Error creating thread */
-      SILC_LOG_DEBUG(("Error creating thread"));
-      f->error = TRUE;
-      silc_fsm_next(fsm, test_st_finish);
-      return SILC_FSM_CONTINUE;
-    }
-
+    silc_fsm_thread_init(&f->threads[i].thread, fsm,
+                        &f->threads[i], NULL, NULL, FALSE);
     silc_fsm_start(&f->threads[i].thread, test_thread3_st_start);
   }
 
@@ -317,15 +299,8 @@ SILC_FSM_STATE(test_st_ninth)
     f->threads2[i].rounds = 10;
     f->threads2[i].f = f;
     silc_fsm_sema_init(&f->threads2[i].sema, fsm, 0);
-    if (!silc_fsm_thread_init(&f->threads2[i].thread, fsm,
-                             &f->threads2[i], NULL, NULL, TRUE)) {
-      /** Error creating real thread */
-      SILC_LOG_DEBUG(("Error creating real thread"));
-      f->error = TRUE;
-      silc_fsm_next(fsm, test_st_finish);
-      return SILC_FSM_CONTINUE;
-    }
-
+    silc_fsm_thread_init(&f->threads2[i].thread, fsm,
+                        &f->threads2[i], NULL, NULL, TRUE);
     silc_fsm_start(&f->threads2[i].thread, test_thread4_st_start);
   }
 
index 380f618228377f5256332de352285010ae48d48d..21b3fca3364c2da61ea6b337d02c9de1b8e57045 100644 (file)
@@ -1,6 +1,6 @@
 /* Hash table tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 typedef struct entry_struct {
   char name[8];
index da34e1b9a8d21cecbf10d28ac52f5606c01cdd07..3b0ad86dbce02400f4de60000e5f6e14f873dd02 100644 (file)
@@ -1,6 +1,6 @@
 /* SilcList tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 struct foo {
   int i;
index a514d55bdd8bc43843fc4350a116893ad5e34d70..65567cdb9ff25f514b1f43f37b7274d47cd25d22 100644 (file)
@@ -1,6 +1,6 @@
 /* SilcMime tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcmime.h"
 
 int main(int argc, char **argv)
@@ -48,7 +48,7 @@ int main(int argc, char **argv)
   SILC_LOG_DEBUG(("Encoded MIME message: \n%s", enc));
   silc_mime_free(mime);
   SILC_LOG_DEBUG(("Decoding MIME message"));
-  mime = silc_mime_decode(enc, enc_len);
+  mime = silc_mime_decode(NULL, enc, enc_len);
   if (!mime)
     goto err;
   SILC_LOG_DEBUG(("Re-encoding MIME context"));
@@ -143,7 +143,7 @@ int main(int argc, char **argv)
   SILC_LOG_DEBUG(("Encoded MIME message: \n%s", enc));
   silc_mime_free(mime);
   SILC_LOG_DEBUG(("Decoding MIME message"));
-  mime = silc_mime_decode(enc, enc_len);
+  mime = silc_mime_decode(NULL, enc, enc_len);
   if (!mime)
     goto err;
   SILC_LOG_DEBUG(("Re-encoding MIME context"));
@@ -210,7 +210,7 @@ int main(int argc, char **argv)
   SILC_LOG_DEBUG(("Defragment"));
   silc_dlist_start(frag);
   while ((buf = silc_dlist_get(frag)) != SILC_LIST_END) {
-    part = silc_mime_decode(buf->data, silc_buffer_len(buf));
+    part = silc_mime_decode(NULL, buf->data, silc_buffer_len(buf));
     if (!silc_mime_is_partial(part))
         goto err;
     part = silc_mime_assemble(ass, part);
index f678b255a23c199090077a9852dbb733757d10b3..19d90a04a804bfcbd2065ae00547692f049c0c78 100644 (file)
@@ -1,6 +1,6 @@
 /* SILC Net API tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 SilcSchedule schedule;
 
@@ -50,7 +50,7 @@ SILC_FSM_STATE(test_st_connect)
   SILC_LOG_DEBUG(("test_st_connect"));
   SILC_LOG_DEBUG(("Connecting to server"));
 
-  silc_fsm_next(fsm, test_st_connected);
+  silc_fsm_next(fsm, test_st_connected, NULL);
   SILC_FSM_CALL(silc_net_tcp_connect(NULL, "localhost", 5000,
                                     silc_fsm_get_schedule(fsm),
                                     test_connected, f));
@@ -88,18 +88,18 @@ SILC_FSM_STATE(test_st_start)
   if (!f->server) {
     /** Creating network listener failed */
     SILC_LOG_DEBUG(("Listener creation failed"));
-    silc_fsm_next(fsm, test_st_finish);
+    silc_fsm_next(fsm, test_st_finish, NULL);
     return SILC_FSM_CONTINUE;
   }
 
   /* Create thread to connect to the listener */
   silc_fsm_thread_init(&f->thread, fsm, f, NULL, NULL, FALSE);
-  silc_fsm_start(&f->thread, test_st_connect);
+  silc_fsm_start(&f->thread, test_st_connect, NULL);
 
   /** Start waiting connection */
   SILC_LOG_DEBUG(("Start waiting for incoming connections"));
   silc_fsm_sema_init(&f->sema, fsm, 0);
-  silc_fsm_next(fsm, test_st_second);
+  silc_fsm_next(fsm, test_st_second, NULL);
   return SILC_FSM_CONTINUE;
 }
 
@@ -116,7 +116,7 @@ SILC_FSM_STATE(test_st_second)
   if (f->client_status != SILC_NET_OK) {
     /** Accepting new connection failed */
     SILC_LOG_DEBUG(("Accepting failed %d", f->client_status));
-    silc_fsm_next(fsm, test_st_finish);
+    silc_fsm_next(fsm, test_st_finish, NULL);
     return SILC_FSM_CONTINUE;
   }
 
@@ -125,7 +125,7 @@ SILC_FSM_STATE(test_st_second)
 
   /** Finish */
   f->success = TRUE;
-  silc_fsm_next(fsm, test_st_finish);
+  silc_fsm_next(fsm, test_st_finish, NULL);
   return SILC_FSM_CONTINUE;
 }
 
@@ -182,7 +182,7 @@ int main(int argc, char **argv)
   fsm = silc_fsm_alloc(f, destructor, NULL, schedule);
   if (!fsm)
     goto err;
-  silc_fsm_start(fsm, test_st_start);
+  silc_fsm_start(fsm, test_st_start, NULL);
   f->fsm = fsm;
 
   SILC_LOG_DEBUG(("Running scheduler"));
index eaf74cb89088ab69f7640c151134d73ed34416f9..b317b18dbb6daa9e84d1831edc0432b24a84a982 100644 (file)
@@ -1,10 +1,10 @@
 /* SilcSchedule tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 typedef void (*Callback)(void *context);
 
-#define NUM_TTASK 20
+#define NUM_TTASK 200
 #ifdef FD_SETSIZE
 #define NUM_FTASK FD_SETSIZE
 #else
@@ -24,8 +24,10 @@ SILC_TASK_CALLBACK(cont)
 
   SILC_LOG_DEBUG(("Adding %d fd tasks", NUM_FTASK - 10));
 
+#if 0
   for (i = 0; i < NUM_FTASK - 10; i++)
     silc_schedule_task_add_fd(schedule, i + 5, foo, (void *)(i + 5));
+#endif
 }
 
 SILC_TASK_CALLBACK(timeout)
@@ -40,9 +42,14 @@ SILC_TASK_CALLBACK(start)
 
   SILC_LOG_DEBUG(("Adding %d timeout tasks", NUM_TTASK));
 
+#if 0
   for (i = 0; i < NUM_TTASK; i++)
     silc_schedule_task_add_timeout(schedule, timeout, (void *)i,
-       0, (i * 720391) & 999999);
+       i + (i & 9999), (i * 720391) & 999999);
+#endif
+
+  for (i = 0; i < NUM_TTASK; i++)
+    silc_schedule_task_add_timeout(schedule, timeout, (void *)i, 0, 1);
 
   silc_schedule_task_add_timeout(schedule, cont, (void *)i, 0, 100);
 }
index 3a50a1cda5ebbc3918237a9d00cb49ce4168bb29..c2416c6db3ebccd66b3aea047042418c4143ef15 100644 (file)
@@ -1,6 +1,6 @@
 /* SilcStack tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #define NUM_ALLS 300
 
index 4810cf9abd895d8cc4a6b368d7da479b64b3fe74..62c0be2eb7b5a2e0079630772c324eb1786642a2 100644 (file)
@@ -1,6 +1,6 @@
 /* Stringprep tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 typedef struct {
   const char *comment;
index dd3354a64e5d5fad6dc2d9a5dd28031da0784ec7..343ab714fc9e93048561f2134c59ae8f55385ff3 100644 (file)
@@ -1,6 +1,6 @@
 /* UTF-8 decoding tests */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #define utf8fail(n, data, len)                 \
 const unsigned char u##n[] = (data);           \
index f368116547d8e873e1799ceebb1a27ef4484ee92..0eae1496ce99ae6162ddb91e6896e1959eec045d 100644 (file)
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* SILC Mutex structure */
 struct SilcMutexStruct {
 #ifdef SILC_THREADS
   pthread_mutex_t mutex;
-  unsigned int locked : 1;
 #else
   void *tmp;
 #endif /* SILC_THREADS */
@@ -37,8 +36,10 @@ SilcBool silc_mutex_alloc(SilcMutex *mutex)
   if (*mutex == NULL)
     return FALSE;
   pthread_mutex_init(&(*mutex)->mutex, NULL);
-#endif /* SILC_THREADS */
   return TRUE;
+#else
+  return FALSE;
+#endif /* SILC_THREADS */
 }
 
 void silc_mutex_free(SilcMutex mutex)
@@ -57,8 +58,6 @@ void silc_mutex_lock(SilcMutex mutex)
   if (mutex) {
     if (pthread_mutex_lock(&mutex->mutex))
       assert(FALSE);
-    assert(mutex->locked == 0);
-    mutex->locked = 1;
   }
 #endif /* SILC_THREADS */
 }
@@ -67,8 +66,6 @@ void silc_mutex_unlock(SilcMutex mutex)
 {
 #ifdef SILC_THREADS
   if (mutex) {
-    assert(mutex->locked == 1);
-    mutex->locked = 0;
     if (pthread_mutex_unlock(&mutex->mutex))
       assert(FALSE);
   }
index 654d8bbef7294989422f0bff702b35bbb6b99c12..1d3364a5568158ead8997c8a166a5f6ae53d4ab6 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcnet.h"
 
 #ifdef HAVE_IPV6
index c0393c7349793a0efd6eb7cddb034304312f7e29..67e8d1d3f654c644ad66e6cfd8fab63da4b70dfc 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #if defined(HAVE_POLL) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
 #include <poll.h>
index 10e6e8418fd0a963d37bdf7ae8ee1974886cf77a..f409689a1ec3cde115e96c21583ae296fb13843a 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* QoS read handler, this will call the read and write events to indicate
    that data is available again after a timeout. */
index 80e1a8e62f30164fc1fa05a37f79b0e243ce5642..099d75d934865fc8846e2326482a7f232c8c1c3e 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 SilcThread silc_thread_create(SilcThreadStart start_func, void *context,
                              SilcBool waitable)
index 93a5fdd2b3c0a4906f0bcd5cbfa9bc9ba04b6cbe..15356c52b92b474f40b0f5e01c27a709920ad948 100644 (file)
@@ -22,7 +22,7 @@
  */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* XXX lib/contrib/regex.c might cmopile on WIN32 as well */
 
index 9037505ad42690487b989ee3887e523018125862..34db890fe8862e17a5cf193c1a91f02280817aaa 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* SILC Mutex structure */
 struct SilcMutexStruct {
@@ -34,9 +34,13 @@ SilcBool silc_mutex_alloc(SilcMutex *mutex)
 {
 #ifdef SILC_THREADS
   *mutex = silc_calloc(1, sizeof(**mutex));
+  if (!(*mutex))
+    return FALSE;
   InitializeCriticalSection(&((*mutex)->mutex));
-#endif /* SILC_THREADS */
   return TRUE;
+#else
+  return FALSE;
+#endif /* SILC_THREADS */
 }
 
 void silc_mutex_free(SilcMutex mutex)
index 6cdad249f2f171fa22949c9a18a8ed6b64f49bc6..818945e0c0ec769a0cd9e6bf4f9b4d3c9d3c5ec9 100644 (file)
@@ -20,7 +20,7 @@
 
 /* XXX IPv6 support missing */
 
-#include "silcincludes.h"
+#include "silc.h"
 #include "silcnet.h"
 
 /* This function creates server or daemon or listener or what ever. This
index 0781ae9b4287ac938235f7fd3c3a1a7437a7cb98..32d345087cca5f4848741846d630ee8077fda68b 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Our "select()" for WIN32. This mimics the behaviour of select() system
    call. It does not call the Winsock's select() though. Its functions
index 8adef30b28cee62841bc3589ffd1c91857134323..31f702f48ec2b913e05b2be89563522e8ac15439 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* Writes data from encrypted buffer to the socket connection. If the
    data cannot be written at once, it will be written later with a timeout. 
index 1fe4bb94e9f8805ad3a9c2b35e105c367c94ec2c..c31e70931381d2f68cecb669bb040f462b102839 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 #ifdef SILC_THREADS
 
index 45c45e6cb2f5be1980ca6f44b457857b70ff4b62..fad5f5996689eeea4831d13130aa5ffac873ed58 100644 (file)
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 
-#include "silcincludes.h"
+#include "silc.h"
 
 /* XXX GNU regex may work on Win32 too!! */
 char *silc_string_regexify(const char *string)